home *** CD-ROM | disk | FTP | other *** search
/ Enter 2004 April / enter-2004-04.iso / files / httrack-3.30.exe / {app} / src / htslib.c < prev    next >
Encoding:
C/C++ Source or Header  |  2003-10-11  |  129.5 KB  |  4,787 lines

  1. /* ------------------------------------------------------------ */
  2. /*
  3. HTTrack Website Copier, Offline Browser for Windows and Unix
  4. Copyright (C) Xavier Roche and other contributors
  5.  
  6. This program is free software; you can redistribute it and/or
  7. modify it under the terms of the GNU General Public License
  8. as published by the Free Software Foundation; either version 2
  9. of the License, or any later version.
  10.  
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with this program; if not, write to the Free Software
  18. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  19.  
  20.  
  21. Important notes:
  22.  
  23. - We hereby ask people using this source NOT to use it in purpose of grabbing
  24. emails addresses, or collecting any other private information on persons.
  25. This would disgrace our work, and spoil the many hours we spent on it.
  26.  
  27.  
  28. Please visit our Website: http://www.httrack.com
  29. */
  30.  
  31.  
  32. /* ------------------------------------------------------------ */
  33. /* File: Subroutines                                            */
  34. /* Author: Xavier Roche                                         */
  35. /* ------------------------------------------------------------ */
  36.  
  37. // Fichier librairie .c
  38.  
  39. #include "htslib.h"
  40. #include "htsbauth.h"
  41.  
  42. /* specific definitions */
  43. #include "htsbase.h"
  44. #include "htsnet.h"
  45. #include "htsbauth.h"
  46. #include "htsthread.h"
  47. #include "htsnostatic.h"
  48. #include "htswrap.h"
  49. #include <stdio.h>
  50. #if HTS_WIN
  51. #include <direct.h>
  52. #else
  53. #ifdef HAVE_SYS_TYPES_H
  54. #include <sys/types.h>
  55. #endif
  56. #ifdef HAVE_SYS_STAT_H
  57. #include <sys/stat.h>
  58. #endif
  59. #ifdef HAVE_UNISTD_H
  60. #include <unistd.h>
  61. #endif
  62. #endif
  63. #include <stdlib.h>
  64. #include <string.h>
  65. #include <time.h>
  66. #include <sys/timeb.h>
  67. #include <fcntl.h>
  68. // pour utimbuf
  69. #if HTS_WIN
  70. #include <sys/utime.h>
  71. #else
  72. #include <utime.h>
  73. #endif
  74. /* END specific definitions */
  75.  
  76.  
  77.  
  78. // DΘbuggage de contr⌠le
  79. #if HTS_DEBUG_CLOSESOCK
  80. #define _HTS_WIDE 1
  81. #endif
  82. #if HTS_WIDE_DEBUG
  83. #define _HTS_WIDE 1
  84. #endif
  85. #if _HTS_WIDE
  86. FILE* DEBUG_fp=NULL;
  87. #define DEBUG_W(A)  { if (DEBUG_fp==NULL) DEBUG_fp=fopen("bug.out","wb"); fprintf(DEBUG_fp,":>"A); fflush(DEBUG_fp); }
  88. #define DEBUG_W2(A) { if (DEBUG_fp==NULL) DEBUG_fp=fopen("bug.out","wb"); fprintf(DEBUG_fp,A); fflush(DEBUG_fp); }
  89. #endif
  90.  
  91. /* variables globales */
  92. int _DEBUG_HEAD;
  93. FILE* ioinfo;
  94.  
  95. #if HTS_USEOPENSSL
  96.  SSL_CTX *openssl_ctx = NULL;
  97. #endif
  98. int IPV6_resolver = 0;
  99.  
  100.  
  101. /* dΘtection complΘmentaire */
  102. const char* hts_detect[] = {
  103.   "archive",
  104.   "background",
  105.   "data",         // OBJECT
  106.   "dynsrc",
  107.   "lowsrc",
  108.   "profile",      // element META
  109.   "src",
  110.   "swurl",
  111.   "url",
  112.   "usemap",
  113.   "longdesc",     // accessibility
  114.   "xlink:href",   // xml/svg tag
  115.   ""
  116. };
  117.  
  118. /* dΘtecter dΘbut */
  119. const char* hts_detectbeg[] = {
  120.   "hotspot",      /* hotspot1=..,hotspot2=.. */
  121.   ""
  122. };
  123.  
  124. /* ne pas dΘtcter de liens dedans */
  125. const char* hts_nodetect[] = {
  126.   "accept-charset",
  127.   "accesskey",
  128.   "action",
  129.   "align",
  130.   "alt",
  131.   "axes",
  132.   "axis",
  133.   "char",
  134.   "charset",
  135.   "cite",
  136.   "class",
  137.   "classid",
  138.   "code",
  139.   "color",
  140.   "datetime",
  141.   "dir",
  142.   "enctype",
  143.   "face",
  144.   "height",
  145.   "id",
  146.   "lang",
  147.   "language",
  148.   "media",
  149.   "method",
  150.   "name",
  151.   "prompt",
  152.   "scheme",
  153.   "size",
  154.   "style",
  155.   "target",
  156.   "title",
  157.   "type",
  158.   "valign",
  159.   "version",
  160.   "width",
  161.   ""
  162. };
  163.  
  164.  
  165. /* dΘtection de mini-code javascript */
  166. /* ALSO USED: detection based on the name: onXXX="<tag>" where XXX starts with upper case letter */
  167. const char* hts_detect_js[] = {
  168.   "onAbort",
  169.   "onBlur",
  170.   "onChange",
  171.   "onClick",
  172.   "onDblClick",
  173.   "onDragDrop",
  174.   "onError",
  175.   "onFocus",
  176.   "onKeyDown",
  177.   "onKeyPress",
  178.   "onKeyUp",
  179.   "onLoad",
  180.   "onMouseDown",
  181.   "onMouseMove",
  182.   "onMouseOut",
  183.   "onMouseOver",
  184.   "onMouseUp",
  185.   "onMove",
  186.   "onReset",
  187.   "onResize",
  188.   "onSelect",
  189.   "onSubmit",
  190.   "onUnload",
  191.   "style",          /* hack for CSS code data */
  192.   ""
  193. };
  194.  
  195. const char* hts_main_mime[] = {
  196.   "application",
  197.   "audio",
  198.   "image",
  199.   "message",
  200.   "multipart",
  201.   "text",
  202.   "video",
  203.   ""
  204. };
  205.  
  206. /* dΘtection "...URL=<url>" */
  207. const char* hts_detectURL[] = {
  208.   "content",
  209.   ""
  210. };
  211.  
  212. /* tags o∙ l'URL doit Ωtre rΘΘcrite mais non capturΘe */
  213. const char* hts_detectandleave[] = {
  214.   "action",
  215.   ""
  216. };
  217.  
  218. /* ne pas renommer les types renvoyΘs (souvent types inconnus) */
  219. const char* hts_mime_keep[] = {
  220.   "application/octet-stream",
  221.   "text/plain",
  222.   ""
  223. };
  224.  
  225. /* pas de type mime connu, mais extension connue */
  226. const char* hts_ext_dynamic[] = {
  227.   "php3",
  228.   "php",
  229.   "php4",
  230.   "php2",
  231.   "cgi",
  232.   "asp",
  233.   "jsp",
  234.   "pl",
  235.   /*"exe",*/
  236.   "cfm",
  237.   "nsf", /* lotus */
  238.   ""
  239. };
  240.  
  241. /* types MIME 
  242.    note: application/octet-stream should not be used here
  243. */
  244. const char* hts_mime[][2] = {
  245.   {"application/acad","dwg"},
  246.   {"application/arj","arj"},
  247.   {"application/clariscad","ccad"},
  248.   {"application/drafting","drw"},
  249.   {"application/dxf","dxf"},
  250.   {"application/excel","xls"},
  251.   {"application/i-deas","unv"},
  252.   {"application/iges","isg"},
  253.   {"application/iges","iges"},
  254.   {"application/mac-binhex40","hqx"},
  255.   {"application/mac-compactpro","cpt"},
  256.   {"application/msword","doc"},
  257.   {"application/msword","w6w"},
  258.   {"application/msword","word"},
  259.   {"application/mswrite","wri"},
  260.   /*{"application/octet-stream","dms"},*/
  261.   /*{"application/octet-stream","lzh"},*/
  262.   /*{"application/octet-stream","lha"},*/
  263.   /*{"application/octet-stream","bin"},*/
  264.   {"application/oda","oda"},
  265.   {"application/pdf","pdf"},
  266.   {"application/postscript","ps"},
  267.   {"application/postscript","ai"},
  268.   {"application/postscript","eps"},
  269.   {"application/powerpoint","ppt"},
  270.   {"application/pro_eng","prt"},
  271.   {"application/pro_eng","part"},
  272.   {"application/rtf","rtf"},
  273.   {"application/set","set"},
  274.   {"application/sla","stl"},
  275.   {"application/smil","smi"},
  276.   {"application/smil","smil"},
  277.   {"application/smil","sml"},
  278.   {"application/solids","sol"},
  279.   {"application/STEP","stp"},
  280.   {"application/STEP","step"},
  281.   {"application/vda","vda"},
  282.   {"application/x-authorware-map","aam"},     
  283.   {"application/x-authorware-seg","aas"},
  284.   {"application/x-authorware-bin","aab"},
  285.   {"application/x-cocoa","cco"},
  286.   {"application/x-csh","csh"},
  287.   {"application/x-director","dir"},
  288.   {"application/x-director","dcr"},
  289.   {"application/x-director","dxr"},
  290.   {"application/x-mif","mif"},
  291.   {"application/x-dvi","dvi"},
  292.   {"application/x-gzip","gz"},
  293.   {"application/x-gzip","gzip"},
  294.   {"application/x-hdf","hdf"},
  295.   {"application/x-javascript","js"},
  296.   {"application/x-koan","skp"},
  297.   {"application/x-koan","skd"},
  298.   {"application/x-koan","skt"},
  299.   {"application/x-koan","skm"},
  300.   {"application/x-latex","latex"},
  301.   {"application/x-netcdf","nc"},
  302.   {"application/x-netcdf","cdf"},
  303.   /* {"application/x-sh","sh"}, */
  304.   /* {"application/x-csh","csh"}, */
  305.   /* {"application/x-ksh","ksh"}, */
  306.   {"application/x-shar","shar"},
  307.   {"application/x-stuffit","sit"},
  308.   {"application/x-tcl","tcl"},
  309.   {"application/x-tex","tex"},
  310.   {"application/x-texinfo","texinfo"},
  311.   {"application/x-texinfo","texi"},
  312.   {"application/x-troff","t"},
  313.   {"application/x-troff","tr"},
  314.   {"application/x-troff","roff"},
  315.   {"application/x-troff-man","man"},
  316.   {"application/x-troff-me","ms"},
  317.   {"application/x-wais-source","src"},
  318.   {"application/zip","zip"},
  319.   {"application/x-zip-compressed","zip"},
  320.   {"application/x-bcpio","bcpio"},
  321.   {"application/x-cdlink","vcd"},
  322.   {"application/x-cpio","cpio"},
  323.   {"application/x-gtar","tgz"},
  324.   {"application/x-gtar","gtar"},
  325.   {"application/x-shar","shar"},
  326.   {"application/x-shockwave-flash","swf"},
  327.   {"application/x-sv4cpio","sv4cpio"},
  328.   {"application/x-sv4crc","sv4crc"},
  329.   {"application/x-tar","tar"},
  330.   {"application/x-ustar","ustar"},
  331.   {"application/x-winhelp","hlp"},
  332.   {"audio/midi","mid"},
  333.   {"audio/midi","midi"},
  334.   {"audio/midi","kar"},
  335.   {"audio/mpeg","mp3"},
  336.   {"audio/mpeg","mpga"},
  337.   {"audio/mpeg","mp2"},
  338.   {"audio/basic","au"},
  339.   {"audio/basic","snd"},
  340.   {"audio/x-aiff","aif"},
  341.   {"audio/x-aiff","aiff"},
  342.   {"audio/x-aiff","aifc"},
  343.   {"audio/x-pn-realaudio","rm"},
  344.   {"audio/x-pn-realaudio","ram"},
  345.   {"audio/x-pn-realaudio","ra"},
  346.   {"audio/x-pn-realaudio-plugin","rpm"},
  347.   {"audio/x-wav","wav"},
  348.   {"chemical/x-pdb","pdb"},
  349.   {"chemical/x-pdb","xyz"},
  350.   {"drawing/x-dwf","dwf"},
  351.   {"image/gif","gif"},
  352.   {"image/ief","ief"},
  353.   {"image/jpeg","jpg"},
  354.   {"image/jpeg","jpe"},
  355.   {"image/jpeg","jpeg"},
  356.   {"image/pict","pict"},
  357.   {"image/png","png"},
  358.   {"image/tiff","tiff"},
  359.   {"image/tiff","tif"},
  360.   {"image/svg+xml","svg"},
  361.   {"image/svg-xml","svg"},
  362.   {"image/x-cmu-raster","ras"},
  363.   {"image/x-freehand","fh4"},
  364.   {"image/x-freehand","fh7"},
  365.   {"image/x-freehand","fh5"},  
  366.   {"image/x-freehand","fhc"},
  367.   {"image/x-freehand","fh"},   
  368.   {"image/x-portable-anymap","pnm"},
  369.   {"image/x-portable-bitmap","pgm"},
  370.   {"image/x-portable-pixmap","ppm"},
  371.   {"image/x-rgb","rgb"},
  372.   {"image/x-xbitmap","xbm"},
  373.   {"image/x-xpixmap","xpm"},
  374.   {"image/x-xwindowdump","xwd"},
  375.   {"model/mesh","msh"},  
  376.   {"model/mesh","mesh"},  
  377.   {"model/mesh","silo"},  
  378.   {"multipart/x-zip","zip"},
  379.   {"multipart/x-gzip","gzip"},
  380.   {"text/css","css"},
  381.   {"text/html","html"},
  382.   {"text/html","htm"},
  383.   {"text/plain","txt"},
  384.   {"text/plain","g"},
  385.   {"text/plain","h"},
  386.   {"text/plain","c"},
  387.   {"text/plain","cc"},
  388.   {"text/plain","hh"},
  389.   {"text/plain","m"},
  390.   {"text/plain","f90"},
  391.   {"text/richtext","rtx"},
  392.   {"text/tab-separated-values","tsv"},
  393.   {"text/x-setext","etx"},
  394.   {"text/x-sgml","sgml"},
  395.   {"text/x-sgml","sgm"},
  396.   {"text/xml","xml"},  
  397.   {"text/xml","dtd"},  
  398.   {"video/mpeg","mpeg"},
  399.   {"video/mpeg","mpg"},
  400.   {"video/mpeg","mpe"},
  401.   {"video/quicktime","qt"},
  402.   {"video/quicktime","mov"},
  403.   {"video/x-msvideo","avi"},
  404.   {"video/x-sgi-movie","movie"},
  405.   {"x-conference/x-cooltalk","ice"},
  406.   /*{"application/x-httpd-cgi","cgi"},*/
  407.   {"x-world/x-vrml","wrl"},
  408.  
  409.   /* More from w3schools.com */
  410.   { "application/envoy", "evy" },
  411.   { "application/fractals", "fif" },
  412.   { "application/futuresplash", "spl" },
  413.   { "application/hta", "hta" },
  414.   { "application/internet-property-stream", "acx" },
  415.   { "application/msword", "dot" },
  416.   { "application/olescript", "axs" },
  417.   { "application/pics-rules", "prf" },
  418.   { "application/pkcs10", "p10" },
  419.   { "application/pkix-crl", "crl" },
  420.   { "application/set-payment-initiation", "setpay" },
  421.   { "application/set-registration-initiation", "setreg" },
  422.   { "application/vnd.ms-excel", "xla" },
  423.   { "application/vnd.ms-excel", "xlc" },
  424.   { "application/vnd.ms-excel", "xlm" },
  425.   { "application/vnd.ms-excel", "xls" },
  426.   { "application/vnd.ms-excel", "xlt" },
  427.   { "application/vnd.ms-excel", "xlw" },
  428.   { "application/vnd.ms-pkicertstore", "sst" },
  429.   { "application/vnd.ms-pkiseccat", "cat" },
  430.   { "application/vnd.ms-powerpoint", "pot" },
  431.   { "application/vnd.ms-powerpoint", "pps" },
  432.   { "application/vnd.ms-powerpoint", "ppt" },
  433.   { "application/vnd.ms-project", "mpp" },
  434.   { "application/vnd.ms-works", "wcm" },
  435.   { "application/vnd.ms-works", "wdb" },
  436.   { "application/vnd.ms-works", "wks" },
  437.   { "application/vnd.ms-works", "wps" },
  438.   { "application/x-compress", "z" },
  439.   { "application/x-compressed", "tgz" },
  440.   { "application/x-internet-signup", "ins" },
  441.   { "application/x-internet-signup", "isp" },
  442.   { "application/x-iphone", "iii" },
  443.   { "application/x-javascript", "js" },
  444.   { "application/x-msaccess", "mdb" },
  445.   { "application/x-mscardfile", "crd" },
  446.   { "application/x-msclip", "clp" },
  447.   { "application/x-msmediaview", "m13" },
  448.   { "application/x-msmediaview", "m14" },
  449.   { "application/x-msmediaview", "mvb" },
  450.   { "application/x-msmetafile", "wmf" },
  451.   { "application/x-msmoney", "mny" },
  452.   { "application/x-mspublisher", "pub" },
  453.   { "application/x-msschedule", "scd" },
  454.   { "application/x-msterminal", "trm" },
  455.   { "application/x-perfmon", "pma" },
  456.   { "application/x-perfmon", "pmc" },
  457.   { "application/x-perfmon", "pml" },
  458.   { "application/x-perfmon", "pmr" },
  459.   { "application/x-perfmon", "pmw" },
  460.   { "application/x-pkcs12", "p12" },
  461.   { "application/x-pkcs12", "pfx" },
  462.   { "application/x-pkcs7-certificates", "p7b" },
  463.   { "application/x-pkcs7-certificates", "spc" },
  464.   { "application/x-pkcs7-certreqresp", "p7r" },
  465.   { "application/x-pkcs7-mime", "p7c" },
  466.   { "application/x-pkcs7-mime", "p7m" },
  467.   { "application/x-pkcs7-signature", "p7s" },
  468.   { "application/x-troff-me", "me" },
  469.   { "application/x-x509-ca-cert", "cer" },
  470.   { "application/x-x509-ca-cert", "crt" },
  471.   { "application/x-x509-ca-cert", "der" },
  472.   { "application/ynd.ms-pkipko", "pko" },
  473.   { "audio/mid", "mid" },
  474.   { "audio/mid", "rmi" },
  475.   { "audio/mpeg", "mp3" },
  476.   { "audio/x-mpegurl", "m3u" },
  477.   { "image/bmp", "bmp" },
  478.   { "image/cis-cod", "cod" },
  479.   { "image/pipeg", "jfif" },
  480.   { "image/x-cmx", "cmx" },
  481.   { "image/x-icon", "ico" },
  482.   { "image/x-portable-bitmap", "pbm" },
  483.   { "message/rfc822", "mht" },
  484.   { "message/rfc822", "mhtml" },
  485.   { "message/rfc822", "nws" },
  486.   { "text/css", "css" },
  487.   { "text/h323", "323" },
  488.   { "text/html", "stm" },
  489.   { "text/iuls", "uls" },
  490.   { "text/plain", "bas" },
  491.   { "text/scriptlet", "sct" },
  492.   { "text/webviewhtml", "htt" },
  493.   { "text/x-component", "htc" },
  494.   { "text/x-vcard", "vcf" },
  495.   { "video/mpeg", "mp2" },
  496.   { "video/mpeg", "mpa" },
  497.   { "video/mpeg", "mpv2" },
  498.   { "video/x-la-asf", "lsf" },
  499.   { "video/x-la-asf", "lsx" },
  500.   { "video/x-ms-asf", "asf" },
  501.   { "video/x-ms-asf", "asr" },
  502.   { "video/x-ms-asf", "asx" },
  503.   { "x-world/x-vrml", "flr" },
  504.   { "x-world/x-vrml", "vrml" },
  505.   { "x-world/x-vrml", "wrz" },
  506.   { "x-world/x-vrml", "xaf" },
  507.   { "x-world/x-vrml", "xof" },
  508.  
  509.   /* Various */
  510.   { "application/ogg", "ogg" },
  511.  
  512.   {"*","class"},
  513.   
  514.   {"",""}};
  515.  
  516.  
  517. // Reserved (RFC2396)
  518. #define CIS(c,ch) ( ((unsigned char)(c)) == (ch) )
  519. #define CHAR_RESERVED(c)  ( CIS(c,';') \
  520.                          || CIS(c,'/') \
  521.                          || CIS(c,'?') \
  522.                          || CIS(c,':') \
  523.                          || CIS(c,'@') \
  524.                          || CIS(c,'&') \
  525.                          || CIS(c,'=') \
  526.                          || CIS(c,'+') \
  527.                          || CIS(c,'$') \
  528.                          || CIS(c,',') )
  529. //#define CHAR_RESERVED(c)  ( strchr(";/?:@&=+$,",(unsigned char)(c)) != 0 )
  530. // Delimiters (RFC2396)
  531. #define CHAR_DELIM(c)     ( CIS(c,'<') \
  532.                          || CIS(c,'>') \
  533.                          || CIS(c,'#') \
  534.                          || CIS(c,'%') \
  535.                          || CIS(c,'\"') )
  536. //#define CHAR_DELIM(c)     ( strchr("<>#%\"",(unsigned char)(c)) != 0 )
  537. // Unwise (RFC2396)
  538. #define CHAR_UNWISE(c)    ( CIS(c,'{') \
  539.                          || CIS(c,'}') \
  540.                          || CIS(c,'|') \
  541.                          || CIS(c,'\\') \
  542.                          || CIS(c,'^') \
  543.                          || CIS(c,'[') \
  544.                          || CIS(c,']') \
  545.                          || CIS(c,'`') )
  546. //#define CHAR_UNWISE(c)    ( strchr("{}|\\^[]`",(unsigned char)(c)) != 0 )
  547. // Special (escape chars) (RFC2396 + >127 )
  548. #define CHAR_LOW(c)       ( ((unsigned char)(c) <= 31) )
  549. #define CHAR_HIG(c)       ( ((unsigned char)(c) >= 127) )
  550. #define CHAR_SPECIAL(c)   ( CHAR_LOW(c) || CHAR_HIG(c) )
  551. // We try to avoid them and encode them instead
  552. #define CHAR_XXAVOID(c)   ( CIS(c,' ') \
  553.                          || CIS(c,'*') \
  554.                          || CIS(c,'\'') \
  555.                          || CIS(c,'\"') \
  556.                          || CIS(c,'!') )
  557. //#define CHAR_XXAVOID(c)   ( strchr(" *'\"!",(unsigned char)(c)) != 0 )
  558. #define CHAR_MARK(c)      ( CIS(c,'-') \
  559.                          || CIS(c,'_') \
  560.                          || CIS(c,'.') \
  561.                          || CIS(c,'!') \
  562.                          || CIS(c,'~') \
  563.                          || CIS(c,'*') \
  564.                          || CIS(c,'\'') \
  565.                          || CIS(c,'(') \
  566.                          || CIS(c,')') )
  567. //#define CHAR_MARK(c)      ( strchr("-_.!~*'()",(unsigned char)(c)) != 0 )
  568.  
  569.  
  570.  
  571. // conversion Θventuelle / vers antislash
  572. #if HTS_WIN
  573. char* antislash(char* s) {
  574.   char* buff;
  575.   char* a;
  576.   NOSTATIC_RESERVE(buff, char, HTS_URLMAXSIZE*2);
  577.  
  578.   strcpybuff(buff,s);
  579.   while(a=strchr(buff,'/')) *a='\\';
  580.   return buff;
  581. }
  582. #endif
  583.  
  584.  
  585.  
  586. // RΘcupΘration d'un fichier http sur le net.
  587. // Renvoie une adresse sur le bloc de mΘmoire, ou bien
  588. // NULL si un retour.msgeur (buffer retour.msg) est survenue. 
  589. //
  590. // Une adresse de structure htsmsg peut Ωtre transmise pour
  591. // suivre l'Θvolution du chargement si le process a ΘtΘ lancΘ 
  592. // en background
  593.  
  594. htsblk httpget(char* url) {
  595.   char adr[HTS_URLMAXSIZE*2];   // adresse
  596.   char fil[HTS_URLMAXSIZE*2];   // chemin
  597.   
  598.   // sΘparer URL en adresse+chemin
  599.   if (ident_url_absolute(url,adr,fil)==-1) {
  600.     htsblk retour;
  601.     memset(&retour, 0, sizeof(htsblk));    // effacer
  602.     // retour prΘdΘfini: erreur
  603.     retour.adr=NULL;
  604.     retour.size=0;
  605.     retour.msg[0]='\0';
  606.     retour.statuscode=-1;    
  607.     strcpybuff(retour.msg,"Error invalid URL");
  608.     return retour;
  609.   }
  610.   
  611.   return xhttpget(adr,fil);
  612. }
  613.  
  614. // ouvre une liaison http, envoie une requΦte GET et rΘceptionne le header
  615. // retour: socket
  616. int http_fopen(char* adr,char* fil,htsblk* retour) {
  617.   //                / GET, traiter en-tΩte
  618.   return http_xfopen(0,1,1,NULL,adr,fil,retour);
  619. }
  620.  
  621. // ouverture d'une liaison http, envoi d'une requΦte
  622. // mode: 0 GET  1 HEAD  [2 POST]
  623. // treat: traiter header?
  624. // waitconnect: attendre le connect()
  625. // note: dans retour, on met les params du proxy
  626. int http_xfopen(int mode,int treat,int waitconnect,char* xsend,char* adr,char* fil,htsblk* retour) {
  627.   //htsblk retour;
  628.   //int bufl=TAILLE_BUFFER;    // 8Ko de buffer
  629.   T_SOC soc=INVALID_SOCKET;
  630.   //char *p,*q;
  631.   
  632.   // retour prΘdΘfini: erreur
  633.   if (retour) {
  634.     retour->adr=NULL;
  635.     retour->size=0;
  636.     retour->msg[0]='\0';
  637.     retour->statuscode=-5;          // a priori erreur non fatale
  638.   }
  639.  
  640. #if HDEBUG
  641.   printf("adr=%s\nfichier=%s\n",adr,fil);
  642. #endif
  643.   
  644.   // ouvrir liaison
  645. #if HDEBUG
  646.   printf("CrΘation d'une socket sur %s\n",adr);
  647. #endif
  648.  
  649. #if CNXDEBUG
  650.   printf("..newhttp\n");
  651. #endif
  652.  
  653.   /* connexion */
  654.   if (retour) {
  655.     if ( (!(retour->req.proxy.active)) 
  656.       ||
  657.       (
  658.         (strcmp(adr,"file://")==0) 
  659.         ||
  660.         (strncmp(adr,"https://", 8)==0) 
  661.       )
  662.       ) {    /* pas de proxy, ou non utilisable ici */
  663.       soc=newhttp(adr,retour,-1,waitconnect);
  664.     } else {
  665.       soc=newhttp(retour->req.proxy.name,retour,retour->req.proxy.port,waitconnect);  // ouvrir sur le proxy α la place
  666.     }
  667.   } else {
  668.     soc=newhttp(adr,NULL,-1,waitconnect);    
  669.   }
  670.  
  671.   // copier index socket retour
  672.   if (retour) retour->soc=soc;
  673.  
  674.   /* Check for errors */
  675.   if (soc == INVALID_SOCKET) {
  676.     if (retour) {
  677.       if (retour->msg) {
  678.         if (!strnotempty(retour->msg)) {
  679.           strcpybuff(retour->msg,"Connect error");
  680.         }
  681.       }
  682.     }
  683.   }
  684.  
  685.   // --------------------
  686.   // court-circuit (court circuite aussi le proxy..)
  687.   // LOCAL_SOCKET_ID est une pseudo-socket locale
  688.   if (soc==LOCAL_SOCKET_ID) {
  689.     retour->is_file=1;  // fichier local
  690.     if (mode==0) {    // GET
  691.  
  692.       // Test en cas de file:///C|...
  693.       if (!fexist(fconv(unescape_http(fil))))
  694.         if (fexist(fconv(unescape_http(fil+1)))) {
  695.           char tempo[HTS_URLMAXSIZE*2];
  696.           strcpybuff(tempo,fil+1);
  697.           strcpybuff(fil,tempo);
  698.         }
  699.  
  700.       // Ouvrir
  701.       retour->totalsize=fsize(fconv(unescape_http(fil)));  // taille du fichier
  702.       retour->msg[0]='\0';
  703.       soc=INVALID_SOCKET;
  704.       if (retour->totalsize<0)
  705.         strcpybuff(retour->msg,"Unable to open local file");
  706.       else if (retour->totalsize==0)
  707.         strcpybuff(retour->msg,"File empty");
  708.       else {
  709.         // Note: On passe par un FILE* (plus propre)
  710.         //soc=open(fil,O_RDONLY,0);    // en lecture seule!
  711.         retour->fp=fopen(fconv(unescape_http(fil)),"rb");  // ouvrir
  712.         if (retour->fp==NULL)
  713.           soc=INVALID_SOCKET;
  714.         else
  715.           soc=LOCAL_SOCKET_ID;
  716.       }
  717.       retour->soc=soc;
  718.       if (soc!=INVALID_SOCKET) {
  719.         retour->statuscode=200;   // OK
  720.         strcpybuff(retour->msg,"OK");
  721.         guess_httptype(retour->contenttype,fil);
  722.       } else if (strnotempty(retour->msg)==0)
  723.           strcpybuff(retour->msg,"Unable to open local file");
  724.       return soc;  // renvoyer
  725.     } else {    // HEAD ou POST : interdit sur un local!!!! (c'est idiot!)
  726.       strcpybuff(retour->msg,"Unexpected Head/Post local request");
  727.       soc=INVALID_SOCKET;    // erreur
  728.       retour->soc=soc;
  729.       return soc;
  730.     }
  731.   } 
  732.   // --------------------
  733.  
  734.   if (soc!=INVALID_SOCKET) {    
  735.     char rcvd[1100];
  736.     rcvd[0]='\0';
  737. #if HDEBUG
  738.     printf("Ok, connexion rΘussie, id=%d\n",soc);
  739. #endif
  740.     
  741.     // connectΘ?
  742.     if (waitconnect) {
  743.       http_sendhead(NULL,mode,xsend,adr,fil,NULL,NULL,retour);
  744.     } 
  745.     
  746.     if (soc!=INVALID_SOCKET) {
  747.       
  748. #if HDEBUG
  749.       printf("Attente de la rΘponse:\n");
  750. #endif
  751.       
  752.       // si GET (rΘception d'un fichier), rΘceptionner en-tΩte d'abord,
  753.       // et ensuite le corps
  754.       // si POST on ne rΘceptionne rien du tout, c'est aprΦs que l'on fera
  755.       // une rΘception standard pour rΘcupΘrer l'en tΩte
  756.       if ((treat) && (waitconnect)) {  // traiter (attendre!) en-tΩte        
  757.         // RΘception de la status line et de l'en-tΩte (norme RFC1945)
  758.         
  759.         // status-line α rΘcupΘrer
  760.         finput(soc,rcvd,1024);
  761.         if (strnotempty(rcvd)==0)
  762.           finput(soc,rcvd,1024);    // "certains serveurs buggΘs envoient un \n au dΘbut" (RFC)
  763.  
  764.         // traiter status-line
  765.         treatfirstline(retour,rcvd);
  766.  
  767. #if HDEBUG
  768.         printf("Status-Code=%d\n",retour->statuscode);
  769. #endif
  770.         
  771.         // en-tΩte
  772.         
  773.         // header // ** !attention! HTTP/0.9 non supportΘ
  774.         do {
  775.           finput(soc,rcvd,1024);          
  776. #if HDEBUG
  777.           printf(">%s\n",rcvd);      
  778. #endif
  779.           if (strnotempty(rcvd))
  780.             treathead(NULL,NULL,NULL,retour,rcvd);  // traiter
  781.  
  782.         } while(strnotempty(rcvd));
  783.         
  784.         //rcvsize=-1;    // forCER CHARGEMENT INCONNU
  785.         
  786.         //if (retour)
  787.         //  retour->totalsize=rcvsize;
  788.         
  789.       } else { // si GET, on recevra l'en tΩte APRES
  790.         //rcvsize=-1;    // on ne connait pas la taille de l'en-tΩte
  791.         if (retour)
  792.           retour->totalsize=-1;
  793.       }
  794.       
  795.     }
  796.  
  797.   }
  798.     
  799.   return soc;
  800. }
  801.  
  802.  
  803. // envoi d'une requΦte
  804. int http_sendhead(t_cookie* cookie,int mode,char* xsend,char* adr,char* fil,char* referer_adr,char* referer_fil,htsblk* retour) {
  805.   char buff[8192];
  806.   //int use_11=0;     // HTTP 1.1 utilisΘ
  807.   int direct_url=0; // ne pas analyser l'url (exemple: ftp://)
  808.   char* search_tag=NULL;
  809.   buff[0]='\0';
  810.  
  811.   // header Date
  812.   //strcatbuff(buff,"Date: ");
  813.   //time_gmt_rfc822(buff);    // obtenir l'heure au format rfc822
  814.   //sendc("\n");
  815.   //strcatbuff(buff,buff);
  816.  
  817.   // possibilitΘ non documentΘe: >post: et >postfile:
  818.   // si prΘsence d'un tag >post: alors executer un POST
  819.   // exemple: http://www.someweb.com/test.cgi?foo>post:posteddata=10&foo=5
  820.   // si prΘsence d'un tag >postfile: alors envoyer en tΩte brut contenu dans le fichier en question
  821.   // exemple: http://www.someweb.com/test.cgi?foo>postfile:post0.txt
  822.   search_tag=strstr(fil,POSTTOK":");
  823.   if (!search_tag) {
  824.     search_tag=strstr(fil,POSTTOK"file:");
  825.     if (search_tag) {     // postfile
  826.       if (mode==0) {      // GET!
  827.         FILE* fp=fopen(unescape_http(search_tag+strlen(POSTTOK)+5),"rb");
  828.         if (fp) {
  829.           char line[1100];
  830.           char protocol[256],url[HTS_URLMAXSIZE*2],method[256];
  831.           linput(fp,line,1000);
  832.           if (sscanf(line,"%s %s %s",method,url,protocol) == 3) {
  833.             // selon que l'on a ou pas un proxy
  834.             if (retour->req.proxy.active)
  835.               sprintf(buff,"%s http://%s%s %s\r\n",method,adr,url,protocol);
  836.             else
  837.               sprintf(buff,"%s %s %s\r\n",method,url,protocol);
  838.             // lire le reste en brut
  839.             fread(buff+strlen(buff),8000-strlen(buff),1,fp);
  840.           }
  841.           fclose(fp);
  842.         }
  843.       }
  844.     }
  845.   }
  846.   // Fin postfile
  847.   
  848.   if (strnotempty(buff)==0) {    // PAS POSTFILE
  849.     // Type de requΦte?
  850.     if ((search_tag) && (mode==0)) {
  851.       strcatbuff(buff,"POST ");
  852.     } else if (mode==0) {    // GET
  853.       strcatbuff(buff,"GET ");
  854.     } else {  // if (mode==1) {
  855.       if (!retour->req.http11)        // forcer HTTP/1.0
  856.         strcatbuff(buff,"GET ");      // certains serveurs (cgi) buggent avec HEAD
  857.       else
  858.         strcatbuff(buff,"HEAD ");
  859.     }
  860.     
  861.     // si on gΦre un proxy, il faut une Absolute URI: on ajoute avant http://www.adr.dom
  862.     if ( retour->req.proxy.active && (strncmp(adr,"https://", 8) != 0) ) {
  863.       if (!link_has_authority(adr)) {  // default http
  864. #if HDEBUG
  865.         printf("Proxy Use: for %s%s proxy %d port %d\n",adr,fil,retour->req.proxy.name,retour->req.proxy.port);
  866. #endif
  867.         strcatbuff(buff,"http://");
  868.         strcatbuff(buff,jump_identification(adr));
  869.       } else {          // ftp:// en proxy http
  870. #if HDEBUG
  871.         printf("Proxy Use for ftp: for %s%s proxy %d port %d\n",adr,fil,retour->req.proxy.name,retour->req.proxy.port);
  872. #endif
  873.         direct_url=1;             // ne pas analyser user/pass
  874.         strcatbuff(buff,adr);
  875.       }
  876.     } 
  877.     
  878.     // NOM DU FICHIER
  879.     // on slash doit Ωtre prΘsent en dΘbut, sinon attention aux bad request! (400)
  880.     if (*fil!='/') strcatbuff(buff,"/");
  881.     {
  882.       char tempo[HTS_URLMAXSIZE*2];
  883.       tempo[0]='\0';
  884.       if (search_tag)
  885.         strncatbuff(tempo,fil,(int) (search_tag - fil));
  886.       else
  887.         strcpybuff(tempo,fil);
  888.       escape_check_url(tempo);
  889.       strcatbuff(buff,tempo);       // avec Θchappement
  890.     }
  891.     
  892.     // protocole
  893.     if (!retour->req.http11) {     // forcer HTTP/1.0
  894.       //use_11=0;
  895.       strcatbuff(buff," HTTP/1.0\x0d\x0a");
  896.     } else {                   // RequΦte 1.1
  897.       //use_11=1;
  898.       strcatbuff(buff," HTTP/1.1\x0d\x0a");
  899.     }
  900.  
  901.     /* supplemental data */
  902.     if (xsend) strcatbuff(buff,xsend);    // Θventuelles autres lignes
  903.  
  904.     // tester proxy authentication
  905.     if (retour->req.proxy.active) {
  906.       if (link_has_authorization(retour->req.proxy.name)) {  // et hop, authentification proxy!
  907.         char* a=jump_identification(retour->req.proxy.name);
  908.         char* astart=jump_protocol(retour->req.proxy.name);
  909.         char autorisation[1100];
  910.         char user_pass[256];        
  911.         autorisation[0]=user_pass[0]='\0';
  912.         //
  913.         strncatbuff(user_pass,astart,(int) (a - astart) - 1);
  914.         strcpybuff(user_pass,unescape_http(user_pass));
  915.         code64((unsigned char*)user_pass,(int)strlen(user_pass),(unsigned char*)autorisation,0);
  916.         strcatbuff(buff,"Proxy-Authorization: Basic ");
  917.         strcatbuff(buff,autorisation);
  918.         strcatbuff(buff,H_CRLF);
  919. #if HDEBUG
  920.         printf("Proxy-Authenticate, %s (code: %s)\n",user_pass,autorisation);
  921. #endif
  922.       }
  923.     }
  924.     
  925.     // Referer?
  926.     if ((referer_adr) && (referer_fil)) {       // existe
  927.       if ((strnotempty(referer_adr)) && (strnotempty(referer_fil))) {   // non vide
  928.         if (
  929.           (strcmp(referer_adr,"file://") != 0)
  930.           &&
  931.           (  /* no https referer to http urls */
  932.             (strncmp(referer_adr, "https://", 8) != 0)  /* referer is not https */
  933.             ||
  934.             (strncmp(adr, "https://", 8) == 0)          /* or referer AND addresses are https */
  935.           )
  936.           ) {      // PAS file://
  937.           strcatbuff(buff,"Referer: ");
  938.           strcatbuff(buff,"http://");
  939.           strcatbuff(buff,jump_identification(referer_adr));
  940.           strcatbuff(buff,referer_fil);
  941.           strcatbuff(buff,H_CRLF);
  942.         }
  943.       }
  944.     }
  945.     
  946.     // POST?
  947.     if (mode==0) {      // GET!
  948.       if (search_tag) {
  949.         char clen[256];
  950.         sprintf(clen,"Content-length: %d"H_CRLF,(int)(strlen(unescape_http(search_tag+strlen(POSTTOK)+1))));
  951.         strcatbuff(buff,clen);
  952.       }
  953.     }
  954.     
  955.     // gestion cookies?
  956.     if (cookie) {
  957.       char* b=cookie->data;
  958.       int cook=0;
  959.       int max_cookies=8;
  960.       int max_size=2048;
  961.       max_size+=strlen(buff);
  962.       do {
  963.         b=cookie_find(b,"",jump_identification(adr),fil);       // prochain cookie satisfaisant aux conditions
  964.         if (b) {
  965.           max_cookies--;
  966.           if (!cook) {
  967.             strcatbuff(buff,"Cookie: ");
  968.             strcatbuff(buff,"$Version=1; ");
  969.             cook=1;
  970.           } else
  971.             strcatbuff(buff,"; ");
  972.           strcatbuff(buff,cookie_get(b,5));
  973.           strcatbuff(buff,"=");
  974.           strcatbuff(buff,cookie_get(b,6));
  975.           strcatbuff(buff,"; $Path=");
  976.           strcatbuff(buff,cookie_get(b,2));
  977.           b=cookie_nextfield(b);
  978.         }
  979.       } while( (b) && (max_cookies>0) && ((int)strlen(buff)<max_size));
  980.       if (cook) {                           // on a envoyΘ un (ou plusieurs) cookie?
  981.         strcatbuff(buff,H_CRLF);
  982. #if DEBUG_COOK
  983.         printf("Header:\n%s\n",buff);
  984. #endif
  985.       }
  986.     }
  987.     
  988.     // gΘrer le keep-alive (garder socket)
  989.     if (retour->req.http11 && !retour->req.nokeepalive) {
  990.             strcatbuff(buff,"Connection: Keep-Alive"H_CRLF);
  991.         } else {
  992.       strcatbuff(buff,"Connection: close"H_CRLF);
  993.         }
  994.     
  995.     {
  996.       char* real_adr=jump_identification(adr);
  997.       //if ((use_11) || (retour->user_agent_send)) {   // Pour le 1.1 on utilise un Host:
  998.       if (!direct_url) {     // pas ftp:// par exemple
  999.         //if (!retour->req.proxy.active) {
  1000.         strcatbuff(buff,"Host: "); strcatbuff(buff,real_adr); strcatbuff(buff,H_CRLF);
  1001.         //}
  1002.       }
  1003.       //}
  1004.  
  1005.       // PrΘsence d'un user-agent?
  1006.       if (retour->req.user_agent_send) {  // ohh un user-agent
  1007.         char s[256];
  1008.         // HyperTextSeeker/"HTSVERSION
  1009.         sprintf(s,"User-Agent: %s"H_CRLF,retour->req.user_agent);
  1010.         strcatbuff(buff,s);
  1011.         
  1012.         // pour les serveurs difficiles
  1013.         strcatbuff(buff,"Accept: "
  1014.                         "image/png, image/jpeg, image/pjpeg, image/x-xbitmap, image/svg+xml"  /* Accepted */
  1015.                         ", "
  1016.                         "image/gif;q=0.9"  /* also accepted but with lower preference */
  1017.                         ", "
  1018.                         "*/*;q=0.1"        /* also accepted but with even lower preference */
  1019.                         H_CRLF);
  1020.         if (strnotempty(retour->req.lang_iso)) {
  1021.           strcatbuff(buff,"Accept-Language: "); strcatbuff(buff,retour->req.lang_iso); strcatbuff(buff,H_CRLF);
  1022.         }
  1023.         strcatbuff(buff,"Accept-Charset: "
  1024.                         "iso-8859-1"       /* we prefer ISO-8859-1 */
  1025.                         ", "
  1026.                         "iso-8859-*;q=0.9" /* or ISO-8859-* */
  1027.                         ", "
  1028.                         "utf-8;q=0.66"     /* UTF8 is also accepted */
  1029.                         ", "
  1030.                         "*;q=0.33"         /* and any other charset */
  1031.                         H_CRLF);   
  1032.         if (retour->req.http11) {
  1033. #if HTS_USEZLIB
  1034.           //strcatbuff(buff,"Accept-Encoding: gzip, deflate, compress, identity"H_CRLF);
  1035.           if (gz_is_available && (!retour->req.range_used) && (!retour->req.nocompression))
  1036.             strcatbuff(buff,"Accept-Encoding: "
  1037.                             "gzip"         /* gzip if the preffered encoding */
  1038.                             ", "
  1039.                             "identity;q=0.9"
  1040.                             H_CRLF);
  1041.           else
  1042.             strcatbuff(buff,"Accept-Encoding: identity"H_CRLF);       /* no compression */
  1043. #else
  1044.           strcatbuff(buff,"Accept-Encoding: identity"H_CRLF);         /* no compression */
  1045. #endif
  1046.         }
  1047.       } else {
  1048.         strcatbuff(buff,"Accept: */*"H_CRLF);         // le minimum
  1049.       }
  1050.  
  1051.       /* Authentification */
  1052.       {
  1053.         char autorisation[1100];
  1054.         char* a;
  1055.         autorisation[0]='\0';
  1056.         if (link_has_authorization(adr)) {  // ohh une authentification!
  1057.           char* a=jump_identification(adr);
  1058.           char* astart=jump_protocol(adr);
  1059.           if (!direct_url) {      // pas ftp:// par exemple
  1060.             char user_pass[256];
  1061.             user_pass[0]='\0';
  1062.             strncatbuff(user_pass,astart,(int) (a - astart) - 1);
  1063.             strcpybuff(user_pass,unescape_http(user_pass));
  1064.             code64((unsigned char*)user_pass,(int)strlen(user_pass),(unsigned char*)autorisation,0);
  1065.             if (strcmp(fil,"/robots.txt"))      /* pas robots.txt */
  1066.               bauth_add(cookie,astart,fil,autorisation);
  1067.           }
  1068.         } else if ( (a=bauth_check(cookie,real_adr,fil)) )
  1069.           strcpybuff(autorisation,a);
  1070.         /* On a une autorisation a donner?  */
  1071.         if (strnotempty(autorisation)) {
  1072.           strcatbuff(buff,"Authorization: Basic ");
  1073.           strcatbuff(buff,autorisation);
  1074.           strcatbuff(buff,H_CRLF);
  1075.         }
  1076.       }
  1077.  
  1078.     }
  1079.     //strcatbuff(buff,"Accept-Language: en\n");
  1080.     //strcatbuff(buff,"Accept-Charset: iso-8859-1,*,utf-8\n");
  1081.     
  1082.     // CRLF de fin d'en tΩte
  1083.     strcatbuff(buff,H_CRLF);
  1084.     
  1085.     // donnΘes complΘmentaires?
  1086.     if (search_tag)
  1087.     if (mode==0)      // GET!
  1088.       strcatbuff(buff,unescape_http(search_tag+strlen(POSTTOK)+1));
  1089.   }
  1090.   
  1091. #if HDEBUG
  1092. #endif
  1093.   if (_DEBUG_HEAD) {
  1094.     if (ioinfo) {
  1095.       fprintf(ioinfo,"[%d] request for %s%s:\r\n",retour->debugid,jump_identification(adr),fil);
  1096.       fprintfio(ioinfo,buff,"<<< ");
  1097.       fprintf(ioinfo,"\r\n");
  1098.       fflush(ioinfo);
  1099.     }
  1100.   }  // Fin test pas postfile
  1101.   //
  1102.  
  1103.   // Callback
  1104. #if HTS_ANALYSTE
  1105.   if (hts_htmlcheck_sendhead != NULL) {
  1106.     int test_head=hts_htmlcheck_sendhead(buff, adr, fil, referer_adr, referer_fil, retour);
  1107.     if (test_head!=1) {
  1108.       deletesoc_r(retour);
  1109.       strcpybuff(retour->msg,"Header refused by external wrapper");
  1110.       retour->soc=INVALID_SOCKET;
  1111.     }
  1112.   }
  1113. #endif
  1114.  
  1115.   // Envoi
  1116.   if (sendc(retour, buff)<0) {  // ERREUR, socket rompue?...
  1117.   //if (sendc(retour->soc,buff) != strlen(buff)) {  // ERREUR, socket rompue?...
  1118.     deletesoc_r(retour);  // fermer tout de mΩme
  1119.     // et tenter de reconnecter
  1120.     
  1121.     strcpybuff(retour->msg,"Write error");
  1122.     retour->soc=INVALID_SOCKET;
  1123.   }
  1124.   
  1125.   // RX'98
  1126.   return 0;
  1127. }
  1128.  
  1129.  
  1130.  
  1131.  
  1132. // traiter 1ere ligne d'en tΩte
  1133. void treatfirstline(htsblk* retour,char* rcvd) {
  1134.   char* a=rcvd;
  1135.   // exemple:
  1136.   // HTTP/1.0 200 OK
  1137.   if (*a) {
  1138.     // note: certains serveurs buggΘs renvoient HTTP/1.0\n200 OK ou " HTTP/1.0 200 OK"
  1139.     while ((*a==' ') || (*a==10) || (*a==13) || (*a==9)) a++;      // Θpurer espaces au dΘbut
  1140.     if (strfield(a, "HTTP/")) {
  1141.       // sauter HTTP/1.x
  1142.       while ((*a!=' ') && (*a!='\0') && (*a!=10) && (*a!=13) && (*a!=9)) a++;   
  1143.       if (*a != '\0') {
  1144.         while ((*a==' ') || (*a==10) || (*a==13) || (*a==9)) a++;      // Θpurer espaces
  1145.         if ((*a>='0') && (*a<='9')) {
  1146.           sscanf(a,"%d",&(retour->statuscode));
  1147.           // sauter 200
  1148.           while ((*a!=' ') && (*a!='\0') && (*a!=10) && (*a!=13) && (*a!=9)) a++;   
  1149.           while ((*a==' ') || (*a==10) || (*a==13) || (*a==9)) a++;      // Θpurer espaces
  1150.           if ((strlen(a) > 1) && (strlen(a) < 64) )                // message retour
  1151.             strcpybuff(retour->msg,a);
  1152.           else
  1153.             infostatuscode(retour->msg,retour->statuscode);
  1154.           // type MIME par dΘfaut2
  1155.           strcpybuff(retour->contenttype,HTS_HYPERTEXT_DEFAULT_MIME);
  1156.         } else {  // pas de code!
  1157.           retour->statuscode=-1;
  1158.           strcpybuff(retour->msg,"Unknown response structure");
  1159.         }
  1160.       } else {  // euhh??
  1161.         retour->statuscode=-1;
  1162.         strcpybuff(retour->msg,"Unknown response structure");
  1163.       }
  1164.     } else {
  1165.             if (*a == '<') {
  1166.         /* This is dirty .. */
  1167.         retour->statuscode=200;
  1168.         retour->keep_alive=0;
  1169.         strcpybuff(retour->msg, "Unknown, assuming junky server");
  1170.         strcpybuff(retour->contenttype,HTS_HYPERTEXT_DEFAULT_MIME);
  1171.             } else if (strnotempty(a)) {
  1172.         retour->statuscode=-1;
  1173.         strcpybuff(retour->msg,"Unknown (not HTTP/xx) response structure");
  1174.       } else {
  1175.         /* This is dirty .. */
  1176.         retour->statuscode=200;
  1177.         retour->keep_alive=0;
  1178.         strcpybuff(retour->msg, "Unknown, assuming junky server");
  1179.         strcpybuff(retour->contenttype,HTS_HYPERTEXT_DEFAULT_MIME);
  1180.       }
  1181.     }
  1182.   } else {  // vide!
  1183.     /*
  1184.     retour->statuscode=-1;
  1185.     strcpybuff(retour->msg,"Empty reponse or internal error");
  1186.     */
  1187.     /* This is dirty .. */
  1188.     retour->statuscode=200;
  1189.     strcpybuff(retour->msg, "Unknown, assuming junky server");
  1190.     strcpybuff(retour->contenttype,HTS_HYPERTEXT_DEFAULT_MIME);
  1191.   }
  1192. }
  1193.  
  1194. // traiter ligne par ligne l'en tΩte
  1195. // gestion des cookies
  1196. void treathead(t_cookie* cookie,char* adr,char* fil,htsblk* retour,char* rcvd) {
  1197.   int p;
  1198.   if ((p=strfield(rcvd,"Content-length:"))!=0) {
  1199. #if HDEBUG
  1200.     printf("ok, Content-length: dΘtectΘ\n");
  1201. #endif
  1202.     sscanf(rcvd+p,LLintP,&(retour->totalsize));
  1203.     if (retour->totalsize == 0) {
  1204.       retour->empty = 1;
  1205.     }
  1206.   }
  1207.   else if ((p=strfield(rcvd,"Content-Disposition:"))!=0) {
  1208.     while(is_realspace(*(rcvd+p))) p++;    // sauter espaces
  1209.     if ((int) strlen(rcvd+p)<250) { // pas trop long?
  1210.       char tmp[256];
  1211.       char *a=NULL,*b=NULL;
  1212.       strcpybuff(tmp,rcvd+p);
  1213.       a=strstr(tmp,"filename=");
  1214.       if (a) {
  1215.         a+=strlen("filename=");
  1216.         while(is_space(*a)) a++;
  1217.         //a=strchr(a,'"');
  1218.         if (a) {
  1219.           char *c=NULL;
  1220.           //a++;      /* jump " */
  1221.           while((c=strchr(a,'/')))    /* skip all / (see RFC2616) */
  1222.             a=c+1;
  1223.           //b=strchr(a+1,'"');
  1224.           b=a+strlen(a)-1;
  1225.           while(is_space(*b)) b--;
  1226.           b++;
  1227.           if (b) {
  1228.             *b='\0';
  1229.             if ((int) strlen(a) < 200) { // pas trop long?
  1230.               strcpybuff(retour->cdispo,a);
  1231.             }
  1232.           }
  1233.         }
  1234.       } 
  1235.     }
  1236.   }
  1237.   else if ((p=strfield(rcvd,"Last-Modified:"))!=0) {
  1238.     while(is_realspace(*(rcvd+p))) p++;    // sauter espaces
  1239.     if ((int) strlen(rcvd+p)<64) { // pas trop long?
  1240.       //struct tm* tm_time=convert_time_rfc822(rcvd+p);
  1241.       strcpybuff(retour->lastmodified,rcvd+p);
  1242.     }
  1243.   }
  1244.   else if ((p=strfield(rcvd,"Date:"))!=0) {
  1245.     if (strnotempty(retour->lastmodified)==0) {          /* pas encore de last-modified */
  1246.       while(is_realspace(*(rcvd+p))) p++;    // sauter espaces
  1247.       if ((int) strlen(rcvd+p)<64) { // pas trop long?
  1248.         //struct tm* tm_time=convert_time_rfc822(rcvd+p);
  1249.         strcpybuff(retour->lastmodified,rcvd+p);
  1250.       }
  1251.     }
  1252.   }
  1253.   else if ((p=strfield(rcvd,"Etag:"))!=0) {   /* Etag */
  1254.     if (retour) {
  1255.       while(is_realspace(*(rcvd+p))) p++;    // sauter espaces
  1256.       if ((int) strlen(rcvd+p)<64)  // pas trop long?
  1257.         strcpybuff(retour->etag,rcvd+p);
  1258.       else    // erreur.. ignorer
  1259.         retour->etag[0]='\0';
  1260.     }
  1261.   }
  1262.   // else if ((p=strfield(rcvd,"Transfer-Encoding: chunked"))!=0) {  // chunk!
  1263.   else if ((p=strfield(rcvd,"Transfer-Encoding:"))!=0) {  // chunk!
  1264.     while(is_realspace(*(rcvd+p))) p++;    // sauter espaces
  1265.     if (strfield(rcvd+p,"chunked")) {
  1266.       retour->is_chunk=1;     // chunked
  1267.       //retour->http11=2;     // chunked
  1268. #if HDEBUG
  1269.       printf("ok, Transfer-Encoding: dΘtectΘ\n");
  1270. #endif
  1271.     }
  1272.   }
  1273.   else if ((p=strfield(rcvd,"Content-type:"))!=0) {
  1274.     if (retour) {
  1275.       char tempo[1100];
  1276.       // Θviter les text/html; charset=foo
  1277.       {
  1278.         char* a=strchr(rcvd+p,';');
  1279.         if (a) {   // extended information
  1280.           *a='\0';
  1281.           a++;
  1282.               while(is_space(*a)) a++;
  1283.           if (strfield(a, "charset")) {
  1284.             a += 7;
  1285.                 while(is_space(*a)) a++;
  1286.             if (*a == '=') {
  1287.               a++;
  1288.                   while(is_space(*a)) a++;
  1289.               if (*a == '\"') a++;
  1290.                   while(is_space(*a)) a++;
  1291.               if (*a) {
  1292.                 char* chs = a;
  1293.                 while(*a && !is_space(*a) && *a != '\"' && *a != ';') a++;
  1294.                 *a = '\0';
  1295.                 if (*chs) {
  1296.                   if (strlen(chs) < sizeof(retour->charset) - 2) {
  1297.                     strcpybuff(retour->charset, chs);
  1298.                   }
  1299.                 }
  1300.               }
  1301.             }
  1302.           }
  1303.         }
  1304.       }
  1305.       sscanf(rcvd+p,"%s",tempo);
  1306.       if (strlen(tempo) < sizeof(retour->contenttype) - 2)    // pas trop long!!
  1307.         strcpybuff(retour->contenttype,tempo);
  1308.       else
  1309.         strcpybuff(retour->contenttype,"application/octet-stream-unknown");    // erreur
  1310.     }
  1311.   }
  1312.   else if ((p=strfield(rcvd,"Content-Range:"))!=0) {
  1313.     char* a=strstr(rcvd+p,"*/");
  1314.     if (a) {
  1315.       if (sscanf(a+2,LLintP,&retour->crange) != 1) {
  1316.         retour->crange=0;
  1317.       }
  1318.     }
  1319.   }
  1320.   else if ((p=strfield(rcvd,"Connection:"))!=0) {
  1321.         char* a = rcvd + p;
  1322.         while(is_space(*a)) a++;
  1323.         if (*a) {
  1324.             if (strfield(a, "Keep-Alive")) {
  1325.         if (!retour->keep_alive) {
  1326.           retour->keep_alive_max = 10;
  1327.           retour->keep_alive_t = 15;
  1328.         }
  1329.         retour->keep_alive = 1;
  1330.       } else {
  1331.                 retour->keep_alive = 0;
  1332.       }
  1333.         }
  1334.     }
  1335.   else if ((p=strfield(rcvd,"Keep-Alive:"))!=0) {
  1336.         char* a = rcvd + p;
  1337.         while(is_space(*a)) a++;
  1338.         if (*a) {
  1339.       char* p;
  1340.       retour->keep_alive = 1;
  1341.       retour->keep_alive_max = 10;
  1342.       retour->keep_alive_t = 15;
  1343.       if ((p=strstr(a, "timeout="))) {
  1344.         p+=strlen("timeout=");
  1345.         sscanf(p, "%d", &retour->keep_alive_t);
  1346.       }
  1347.       if ((p=strstr(a, "max="))) {
  1348.         p+=strlen("max=");
  1349.         sscanf(p, "%d", &retour->keep_alive_max);
  1350.       }
  1351.       if (retour->keep_alive_max <= 1 || retour->keep_alive_t < 3) {
  1352.         retour->keep_alive = 0;
  1353.       }
  1354.     }
  1355.   }
  1356.   else if ((p=strfield(rcvd,"TE:"))!=0) {
  1357.         char* a = rcvd + p;
  1358.         while(is_space(*a)) a++;
  1359.         if (*a) {
  1360.       if (strfield(a, "trailers")) {
  1361.         retour->keep_alive_trailers=1;
  1362.       }
  1363.     }
  1364.   }
  1365.     else if ((p=strfield(rcvd,"Content-Encoding:"))!=0) {
  1366.         if (retour) {
  1367.             char tempo[1100];
  1368.       char* a = rcvd + p;
  1369.       while(is_space(*a)) a++;
  1370.             {
  1371.                 char* a=strchr(rcvd+p,';');
  1372.                 if (a) *a='\0';
  1373.             }
  1374.             sscanf(a,"%s",tempo);
  1375.       if (strlen(tempo)<64)    // pas trop long!!
  1376.         strcpybuff(retour->contentencoding,tempo);
  1377.       else
  1378.         retour->contentencoding[0]='\0';    // erreur
  1379. #if HTS_USEZLIB
  1380.       /* Check known encodings */
  1381.       if (retour->contentencoding[0]) {
  1382.         if (
  1383.           (strfield2(retour->contentencoding, "gzip"))
  1384.           || (strfield2(retour->contentencoding, "x-gzip"))
  1385.           /*
  1386.           || (strfield2(retour->contentencoding, "compress"))
  1387.           || (strfield2(retour->contentencoding, "x-compress"))
  1388.           */
  1389.           || (strfield2(retour->contentencoding, "deflate"))
  1390.           || (strfield2(retour->contentencoding, "x-deflate"))
  1391.           ) {
  1392.         retour->compressed=1;
  1393.         }
  1394.       }
  1395. #endif
  1396.     }
  1397.   }
  1398.   else if ((p=strfield(rcvd,"Location:"))!=0) {
  1399.     if (retour) {
  1400.       if (retour->location) {
  1401.         while(is_realspace(*(rcvd+p))) p++;    // sauter espaces
  1402.         if ((int) strlen(rcvd+p)<HTS_URLMAXSIZE)  // pas trop long?
  1403.           strcpybuff(retour->location,rcvd+p);
  1404.         else    // erreur.. ignorer
  1405.           retour->location[0]='\0';
  1406.       }
  1407.     }
  1408.   }
  1409.   else if ( ((p=strfield(rcvd,"Set-Cookie:"))!=0) && (cookie) ) {    // ohh un cookie
  1410.     char* a = rcvd+p;           // pointeur
  1411.     char domain[256];           // domaine cookie (.netscape.com)
  1412.     char path[256];             // chemin (/)
  1413.     char cook_name[256];        // nom cookie (MYCOOK)
  1414.     char cook_value[8192];      // valeur (ID=toto,S=1234)
  1415. #if DEBUG_COOK
  1416.     printf("set-cookie detected\n");
  1417. #endif
  1418.     while(*a) {
  1419.       char *token_st,*token_end;
  1420.       char *value_st,*value_end;
  1421.       char name[256];
  1422.       char value[8192];
  1423.       int next=0;
  1424.       name[0]=value[0]='\0';
  1425.       //
  1426.  
  1427.       // initialiser cookie lu actuellement
  1428.       if (adr)
  1429.         strcpybuff(domain,jump_identification(adr));     // domaine
  1430.       strcpybuff(path,"/");         // chemin (/)
  1431.       strcpybuff(cook_name,"");     // nom cookie (MYCOOK)
  1432.       strcpybuff(cook_value,"");    // valeur (ID=toto,S=1234)
  1433.       // boucler jusqu'au prochain cookie ou la fin
  1434.       do {
  1435.         char* start_loop=a;
  1436.         while(is_space(*a)) a++;    // sauter espaces
  1437.         token_st=a;                 // dΘpart token
  1438.         while((!is_space(*a)) && (*a) && (*a!=';') && (*a!='=')) a++;    // arrΩter si espace, point virgule
  1439.         token_end=a;
  1440.         while(is_space(*a)) a++;    // sauter espaces
  1441.         if (*a=='=') {    // name=value
  1442.           a++;
  1443.           while(is_space(*a)) a++;    // sauter espaces
  1444.           value_st=a;
  1445.           while( (*a!=';') && (*a)) a++;    // prochain ;
  1446.           //while( ((*a!='"') || (*(a-1)=='\\')) && (*a)) a++;    // prochain " (et pas \")
  1447.           value_end=a;
  1448.           //if (*a==';') {  // finit par un ;
  1449.           // vΘrifier dΘbordements
  1450.           if ( (((int) (token_end - token_st))<200) && (((int) (value_end - value_st))<8000)
  1451.             && (((int) (token_end - token_st))>0)   && (((int) (value_end - value_st))>0) ) {
  1452.             name[0]='\0';
  1453.             value[0]='\0';
  1454.             strncatbuff(name,token_st,(int) (token_end - token_st));
  1455.             strncatbuff(value,value_st,(int) (value_end - value_st));
  1456. #if DEBUG_COOK
  1457.             printf("detected cookie-av: name=\"%s\" value=\"%s\"\n",name,value);
  1458. #endif
  1459.             if (strfield2(name,"domain")) {
  1460.               strcpybuff(domain,value);
  1461.             }
  1462.             else if (strfield2(name,"path")) {
  1463.               strcpybuff(path,value);
  1464.             }
  1465.             else if (strfield2(name,"max-age")) {
  1466.               // ignorΘ..
  1467.             }
  1468.             else if (strfield2(name,"expires")) {
  1469.               // ignorΘ..
  1470.             }
  1471.             else if (strfield2(name,"version")) {
  1472.               // ignorΘ..
  1473.             }
  1474.             else if (strfield2(name,"comment")) {
  1475.               // ignorΘ
  1476.             }
  1477.             else if (strfield2(name,"secure")) {    // ne devrait pas arriver ici
  1478.               // ignorΘ
  1479.             }
  1480.             else {
  1481.               if (strnotempty(cook_name)==0) {          // noter premier: nom et valeur cookie
  1482.                 strcpybuff(cook_name,name);
  1483.                 strcpybuff(cook_value,value);
  1484.               } else {                             // prochain cookie
  1485.                 a=start_loop;      // on devra recommencer α cette position
  1486.                 next=1;            // enregistrer
  1487.               }
  1488.             }
  1489.           }
  1490.         }
  1491.         if (!next) {
  1492.           while((*a!=';') && (*a)) a++;    // prochain
  1493.           while(*a==';') a++;             // sauter ;
  1494.         }
  1495.       } while((*a) && (!next));
  1496.       if (strnotempty(cook_name)) {          // cookie?
  1497. #if DEBUG_COOK
  1498.         printf("new cookie: name=\"%s\" value=\"%s\" domain=\"%s\" path=\"%s\"\n",cook_name,cook_value,domain,path);
  1499. #endif
  1500.         cookie_add(cookie,cook_name,cook_value,domain,path);
  1501.       }
  1502.     }
  1503.   }
  1504. }
  1505.  
  1506.  
  1507. // transforme le message statuscode en chaεne
  1508. HTSEXT_API void infostatuscode(char* msg,int statuscode) {
  1509.   switch( statuscode) {    
  1510.     // Erreurs HTTP, selon RFC
  1511.   case 100: strcpybuff( msg,"Continue"); break; 
  1512.   case 101: strcpybuff( msg,"Switching Protocols"); break; 
  1513.   case 200: strcpybuff( msg,"OK"); break; 
  1514.   case 201: strcpybuff( msg,"Created"); break; 
  1515.   case 202: strcpybuff( msg,"Accepted"); break; 
  1516.   case 203: strcpybuff( msg,"Non-Authoritative Information"); break; 
  1517.   case 204: strcpybuff( msg,"No Content"); break; 
  1518.   case 205: strcpybuff( msg,"Reset Content"); break; 
  1519.   case 206: strcpybuff( msg,"Partial Content"); break; 
  1520.   case 300: strcpybuff( msg,"Multiple Choices"); break; 
  1521.   case 301: strcpybuff( msg,"Moved Permanently"); break; 
  1522.   case 302: strcpybuff( msg,"Moved Temporarily"); break; 
  1523.   case 303: strcpybuff( msg,"See Other"); break; 
  1524.   case 304: strcpybuff( msg,"Not Modified"); break; 
  1525.   case 305: strcpybuff( msg,"Use Proxy"); break; 
  1526.   case 306: strcpybuff( msg,"Undefined 306 error"); break; 
  1527.   case 307: strcpybuff( msg,"Temporary Redirect"); break; 
  1528.   case 400: strcpybuff( msg,"Bad Request"); break; 
  1529.   case 401: strcpybuff( msg,"Unauthorized"); break; 
  1530.   case 402: strcpybuff( msg,"Payment Required"); break; 
  1531.   case 403: strcpybuff( msg,"Forbidden"); break; 
  1532.   case 404: strcpybuff( msg,"Not Found"); break; 
  1533.   case 405: strcpybuff( msg,"Method Not Allowed"); break; 
  1534.   case 406: strcpybuff( msg,"Not Acceptable"); break; 
  1535.   case 407: strcpybuff( msg,"Proxy Authentication Required"); break; 
  1536.   case 408: strcpybuff( msg,"Request Time-out"); break; 
  1537.   case 409: strcpybuff( msg,"Conflict"); break; 
  1538.   case 410: strcpybuff( msg,"Gone"); break; 
  1539.   case 411: strcpybuff( msg,"Length Required"); break; 
  1540.   case 412: strcpybuff( msg,"Precondition Failed"); break; 
  1541.   case 413: strcpybuff( msg,"Request Entity Too Large"); break; 
  1542.   case 414: strcpybuff( msg,"Request-URI Too Large"); break; 
  1543.   case 415: strcpybuff( msg,"Unsupported Media Type"); break; 
  1544.   case 416: strcpybuff( msg,"Requested Range Not Satisfiable"); break; 
  1545.   case 417: strcpybuff( msg,"Expectation Failed"); break; 
  1546.   case 500: strcpybuff( msg,"Internal Server Error"); break; 
  1547.   case 501: strcpybuff( msg,"Not Implemented"); break; 
  1548.   case 502: strcpybuff( msg,"Bad Gateway"); break; 
  1549.   case 503: strcpybuff( msg,"Service Unavailable"); break; 
  1550.   case 504: strcpybuff( msg,"Gateway Time-out"); break; 
  1551.   case 505: strcpybuff( msg,"HTTP Version Not Supported"); break; 
  1552.     //
  1553.   default: if (strnotempty(msg)==0) strcpybuff( msg,"Unknown error"); break;
  1554.   }
  1555. }
  1556.  
  1557.  
  1558. // identique au prΘcΘdent, sauf que l'on donne adr+fil et non url complΦte
  1559. htsblk xhttpget(char* adr,char* fil) {
  1560.   T_SOC soc;
  1561.   htsblk retour;
  1562.   
  1563.   memset(&retour, 0, sizeof(htsblk));
  1564.   soc=http_fopen(adr,fil,&retour);
  1565.  
  1566.   if (soc!=INVALID_SOCKET) {
  1567.     http_fread(soc,&retour);
  1568. #if HTS_DEBUG_CLOSESOCK
  1569.     DEBUG_W("xhttpget: deletehttp\n");
  1570. #endif
  1571.     if (retour.soc!=INVALID_SOCKET) deletehttp(&retour);  // fermer
  1572.     retour.soc=INVALID_SOCKET;
  1573.   }
  1574.   return retour;
  1575. }
  1576.  
  1577. // variation sur un thΦme...
  1578. // rΘceptionne uniquement un en-tΩte (HEAD)
  1579. // retourne dans xx.adr l'adresse pointant sur le bloc de mΘmoire de l'en tΩte
  1580. htsblk http_gethead(char* adr,char* fil) {
  1581.   T_SOC soc;
  1582.   htsblk retour;
  1583.  
  1584.   memset(&retour, 0, sizeof(htsblk));
  1585.   soc=http_xfopen(1,0,1,NULL,adr,fil,&retour);  // HEAD, pas de traitement en-tΩte
  1586.  
  1587.   if (soc!=INVALID_SOCKET) {
  1588.     http_fread(soc,&retour);    // rΘception en-tΩte
  1589. #if HTS_DEBUG_CLOSESOCK
  1590.     DEBUG_W("http_gethead: deletehttp\n");
  1591. #endif
  1592.     if (retour.soc!=INVALID_SOCKET) deletehttp(&retour);  // fermer
  1593.     retour.soc=INVALID_SOCKET;
  1594.   }
  1595.   return retour;
  1596. }
  1597. // oui ca ressemble vachement α xhttpget - en Θtant sobre on peut voir LA diffΘrence..
  1598.  
  1599.  
  1600. // lecture sur une socket ouverte, le header a dΘja ΘtΘ envoyΘ dans le cas de GET
  1601. // il ne reste plus qu'α lire les donnΘes
  1602. // (pour HEAD le header est lu ici!)
  1603. void http_fread(T_SOC soc,htsblk* retour) {  
  1604.   //int bufl=TAILLE_BUFFER;    // 8Ko de buffer
  1605.   
  1606.   if (retour) retour->soc=soc;
  1607.   if (soc!=INVALID_SOCKET) {    
  1608.     // fonction de lecture d'une socket (plus propre)
  1609.     while(http_fread1(retour)!=-1);
  1610.     soc=retour->soc;
  1611.     if (retour->adr==NULL) {
  1612.       if (strnotempty(retour->msg)==0)
  1613.         sprintf(retour->msg,"Unable to read");
  1614.       return ;    // erreur
  1615.     } 
  1616.     
  1617. #if HDEBUG
  1618.     printf("Ok, donnΘes reτues\n");
  1619. #endif   
  1620.  
  1621.     return ;
  1622.     
  1623.   } 
  1624.   
  1625.   return ;
  1626. }
  1627.  
  1628. // check if data is available
  1629. int check_readinput(htsblk* r) {
  1630.   if (r->soc != INVALID_SOCKET) {
  1631.     fd_set fds;           // poll structures
  1632.     struct timeval tv;          // structure for select
  1633.     FD_ZERO(&fds);
  1634.     FD_SET(r->soc,&fds);           
  1635.     tv.tv_sec=0;
  1636.     tv.tv_usec=0;
  1637.     select(r->soc + 1,&fds,NULL,NULL,&tv);
  1638.     if (FD_ISSET(r->soc,&fds))
  1639.       return 1;
  1640.     else
  1641.       return 0;
  1642.   } else
  1643.     return 0;
  1644. }
  1645.  
  1646. // check if data is available
  1647. int check_readinput_t(T_SOC soc, int timeout) {
  1648.   if (soc != INVALID_SOCKET) {
  1649.     fd_set fds;           // poll structures
  1650.     struct timeval tv;          // structure for select
  1651.     FD_ZERO(&fds);
  1652.     FD_SET(soc,&fds);           
  1653.     tv.tv_sec=timeout;
  1654.     tv.tv_usec=0;
  1655.     select(soc + 1,&fds,NULL,NULL,&tv);
  1656.     if (FD_ISSET(soc,&fds))
  1657.       return 1;
  1658.     else
  1659.       return 0;
  1660.   } else
  1661.     return 0;
  1662. }
  1663.  
  1664.  
  1665. // lecture d'un bloc sur une socket (ou un fichier!)
  1666. // >=0 : nombre d'octets lus
  1667. // <0 : fin ou erreur
  1668. HTS_INLINE LLint http_fread1(htsblk* r) {
  1669.   //int bufl=TAILLE_BUFFER;  // taille d'un buffer max.
  1670.   return http_xfread1(r,TAILLE_BUFFER);
  1671. }
  1672.  
  1673. // idem, sauf qu'ici on peut choisir la taille max de donnΘes α recevoir
  1674. // SI bufl==0 alors le buffer est censΘ Ωtre de 8kos, et on recoit par bloc de lignes
  1675. // en Θliminant les cr (ex: header), arrΩt si double-lf
  1676. // SI bufl==-1 alors le buffer est censΘ Ωtre de 8kos, et on recoit ligne par ligne
  1677. // en Θliminant les cr (ex: header), arrΩt si double-lf
  1678. // Note: les +1 dans les malloc sont d√s α l'octet nul rajoutΘ en fin de fichier
  1679. LLint http_xfread1(htsblk* r,int bufl) {
  1680.   int nl=-1;
  1681.  
  1682.   if (bufl>0) {
  1683.     if (!r->is_write) {     // stocker en mΘmoire
  1684.       if (r->totalsize>0) {    // totalsize dΘterminΘ ET ALLOUE
  1685.         if (r->adr==NULL) {
  1686.           r->adr=(char*) malloct((INTsys) r->totalsize + 1);
  1687.           r->size=0;
  1688.         }
  1689.         if (r->adr!=NULL) {
  1690.           // lecture
  1691.           nl = hts_read(r,r->adr + ((int) r->size),(int) (r->totalsize-r->size) );     /* NO 32 bit overlow possible here (no 4GB html!) */
  1692.           // nouvelle taille
  1693.           if (nl >= 0) r->size+=nl;
  1694.           
  1695.           if ((nl < 0) || (r->size >= r->totalsize))
  1696.             nl=-1;  // break
  1697.           
  1698.           r->adr[r->size]='\0';    // caractΦre NULL en fin au cas o∙ l'on traite des HTML
  1699.         }
  1700.         
  1701.       } else {                 // inconnu..
  1702.         // rΘserver de la mΘmoire?
  1703.         if (r->adr==NULL) {
  1704. #if HDEBUG
  1705.           printf("..alloc xfread\n");
  1706. #endif
  1707.           r->adr=(char*) malloct(bufl + 1);
  1708.           r->size=0;
  1709.         }
  1710.         else {
  1711. #if HDEBUG
  1712.           printf("..realloc xfread1\n");
  1713. #endif
  1714.           r->adr=(char*) realloct(r->adr,(int)r->size+bufl + 1);
  1715.         }
  1716.         
  1717.         if (r->adr!=NULL) {
  1718.           // lecture
  1719.           nl = hts_read(r,r->adr+(int)r->size,bufl);
  1720.           if (nl>0) {
  1721.             // resize
  1722.             r->adr=(char*) realloct(r->adr,(int)r->size+nl + 1);
  1723.             // nouvelle taille
  1724.             r->size+=nl;
  1725.             // octet nul
  1726.             if (r->adr) r->adr[r->size]='\0';
  1727.  
  1728.           } // sinon on a fini
  1729. #if HDEBUG
  1730.           else if (nl < 0)
  1731.             printf("..end read (%d)\n", nl);
  1732. #endif
  1733.         }
  1734. #if HDEBUG
  1735.         else printf("..-> error\n");
  1736. #endif
  1737.       }
  1738.  
  1739.       // pas de adr=erreur
  1740.       if (r->adr==NULL) nl=-1;
  1741.  
  1742.     } else {    // stocker sur disque
  1743.       char* buff;
  1744.       buff=(char*) malloct(bufl);
  1745.       if (buff!=NULL) {
  1746.         // lecture
  1747.         nl = hts_read(r,buff,bufl);
  1748.         // nouvelle taille
  1749.         if (nl > 0) { 
  1750.           r->size+=nl;
  1751.           if ((INTsys)fwrite(buff,1,nl,r->out)!=nl) {
  1752.             r->statuscode=-1;
  1753.             strcpybuff(r->msg,"Write error on disk");
  1754.             nl=-1;
  1755.           }
  1756.         }
  1757.  
  1758.         if ((nl < 0) || ((r->totalsize>0) && (r->size >= r->totalsize)))
  1759.           nl=-1;  // break
  1760.  
  1761.         // libΘrer bloc tempo
  1762.         freet(buff);
  1763.       } else
  1764.         nl=-1;
  1765.       
  1766.       if ((nl < 0) && (r->out!=NULL)) {
  1767.         fflush(r->out); 
  1768.       }
  1769.         
  1770.         
  1771.     } // stockage disque ou mΘmoire
  1772.  
  1773.   } else if (bufl == -2) {  // force reserve
  1774.     if (r->adr==NULL) {
  1775.       r->adr=(char*) malloct(8192);
  1776.       r->size=0;
  1777.       return 0;
  1778.     }
  1779.     return -1;
  1780.   } else {    // rΘception d'un en-tΩte octet par octet
  1781.     int count=256;
  1782.     int tot_nl=0;
  1783.     int lf_detected=0;
  1784.     int at_begining=1;
  1785.     do {
  1786.       nl=-1;
  1787.       count--;
  1788.       if (r->adr==NULL) {
  1789.         r->adr=(char*) malloct(8192);
  1790.         r->size=0;
  1791.       }
  1792.       if (r->adr!=NULL) {
  1793.         if (r->size < 8190) {
  1794.           // lecture
  1795.           nl = hts_read(r,r->adr+r->size,1);
  1796.           if (nl>0) {
  1797.             // exit if:
  1798.             // lf detected AND already detected before
  1799.             // or
  1800.             // lf detected AND first character read
  1801.             if (*(r->adr+r->size) == 10) {
  1802.               if (lf_detected || (at_begining) || (bufl<0))
  1803.                 count=-1;
  1804.               lf_detected=1;
  1805.             }
  1806.             if (*(r->adr+r->size) != 13) {   // sauter caractΦres 13
  1807.               if (
  1808.                 (*(r->adr+r->size) != 10)
  1809.                 &&
  1810.                 (*(r->adr+r->size) != 13)
  1811.                 ) {
  1812.                 // restart for new line
  1813.                 lf_detected=0;
  1814.               }
  1815.               (r->size)++;
  1816.               at_begining=0;
  1817.             }
  1818.             *(r->adr+r->size)='\0';    // terminer par octet nul
  1819.           }
  1820.         }
  1821.       }
  1822.       if (nl >= 0) {
  1823.         tot_nl+=nl;
  1824.         if (!check_readinput(r))
  1825.           count=-1;
  1826.       }
  1827.     } while((nl >= 0) && (count>0));
  1828.     nl = tot_nl;
  1829.   }
  1830. #if HDEBUG
  1831.   //printf("add to %d / %d\n",r->size,r->totalsize);
  1832. #endif
  1833.   // nl == 0 may mean "no relevant data", for example is using cache or ssl
  1834. #if HTS_USEOPENSSL
  1835.   if (r->ssl)
  1836.     return nl;
  1837.   else
  1838. #endif
  1839.     return ((nl > 0) ? nl : -1);        // ==0 is fatal if direct read
  1840. }
  1841.  
  1842.  
  1843. // teste une adresse, et suit l'Θventuel chemin "moved"
  1844. // retourne 200 ou le code d'erreur (404=NOT FOUND, etc)
  1845. // copie dans loc la vΘritable adresse si celle-ci est diffΘrente
  1846. htsblk http_location(char* adr,char* fil,char* loc) {
  1847.   htsblk retour;
  1848.   int retry=0;
  1849.   int tryagain;
  1850.   // note: "RFC says"
  1851.   // 5 boucles au plus, on en teste au plus 8 ici
  1852.   // sinon abandon..
  1853.   do {
  1854.     tryagain=0;
  1855.     switch ((retour=http_test(adr,fil,loc)).statuscode) {
  1856.     case 200: break;   // ok!
  1857.     case 301: case 302: case 303: case 307: // moved!
  1858.       // recalculer adr et fil!
  1859.       if (ident_url_absolute(loc,adr,fil)!=-1) {
  1860.         tryagain=1;  // retenter
  1861.         retry++;     // ..encore une fois
  1862.       }
  1863.     }
  1864.   } while((tryagain) && (retry<5+3));
  1865.   return retour;
  1866. }
  1867.  
  1868.  
  1869. // teste si une URL (validitΘ, header, taille)
  1870. // retourne 200 ou le code d'erreur (404=NOT FOUND, etc)
  1871. // en cas de moved xx, dans location
  1872. // abandonne dΘsormais au bout de 30 secondes (aurevoir les sites
  1873. // qui nous font poireauter 5 heures..) -> -2=timeout
  1874. htsblk http_test(char* adr,char* fil,char* loc) {
  1875.   T_SOC soc;
  1876.   htsblk retour;
  1877.   //int rcvsize=-1;
  1878.   //char* rcv=NULL;    // adresse de retour
  1879.   //int bufl=TAILLE_BUFFER;    // 8Ko de buffer
  1880.   TStamp tl;
  1881.   int timeout=30;  // timeout pour un check (arbitraire) // **
  1882.  
  1883.   // pour abandonner un site trop lent
  1884.   tl=time_local();
  1885.  
  1886.   loc[0]='\0';
  1887.   memset(&retour, 0, sizeof(htsblk));    // effacer
  1888.   retour.location=loc;    // si non nul, contiendra l'adresse vΘritable en cas de moved xx
  1889.  
  1890.   //soc=http_fopen(adr,fil,&retour,NULL);  // ouvrir, + header
  1891.  
  1892.   // on ouvre en head, et on traite l'en tΩte
  1893.   soc=http_xfopen(1,0,1,NULL,adr,fil,&retour);  // ouvrir HEAD, + envoi header
  1894.   
  1895.   if (soc!=INVALID_SOCKET) {
  1896.     int e=0;
  1897.     // tant qu'on a des donnΘes, et qu'on ne recoit pas deux LF, et que le timeout n'arrie pas
  1898.     do {
  1899.       if (http_xfread1(&retour,0) < 0)
  1900.         e=1;
  1901.       else {
  1902.         if (retour.adr!=NULL) {
  1903.           if ((retour.adr[retour.size-1]!=10) || (retour.adr[retour.size-2]!=10))
  1904.             e=1;
  1905.         }
  1906.       }
  1907.             
  1908.       if (!e) {
  1909.         if ((time_local()-tl)>=timeout) {
  1910.           e=-1;
  1911.         }
  1912.       }
  1913.       
  1914.     } while (!e);
  1915.     
  1916.     if (e==1) {
  1917.       if (adr!=NULL) {
  1918.         int ptr=0;
  1919.         char rcvd[1100];
  1920.  
  1921.         // note: en gros recopie du traitement de back_wait()
  1922.         //
  1923.  
  1924.  
  1925.         // ----------------------------------------
  1926.         // traiter en-tΩte!
  1927.         // status-line α rΘcupΘrer
  1928.         ptr+=binput(retour.adr+ptr,rcvd,1024);
  1929.         if (strnotempty(rcvd)==0)
  1930.           ptr+=binput(retour.adr+ptr,rcvd,1024);    // "certains serveurs buggΘs envoient un \n au dΘbut" (RFC)
  1931.         
  1932.         // traiter status-line
  1933.         treatfirstline(&retour,rcvd);
  1934.         
  1935. #if HDEBUG
  1936.         printf("(Buffer) Status-Code=%d\n",retour.statuscode);
  1937. #endif
  1938.         
  1939.         // en-tΩte
  1940.         
  1941.         // header // ** !attention! HTTP/0.9 non supportΘ
  1942.         do {
  1943.           ptr+=binput(retour.adr+ptr,rcvd,1024);          
  1944. #if HDEBUG
  1945.           printf("(buffer)>%s\n",rcvd);      
  1946. #endif
  1947.           if (strnotempty(rcvd))
  1948.             treathead(NULL,NULL,NULL,&retour,rcvd);  // traiter
  1949.           
  1950.         } while(strnotempty(rcvd));
  1951.         // ----------------------------------------                    
  1952.         
  1953.         // libΘrer mΘmoire
  1954.         if (retour.adr!=NULL) { freet(retour.adr); retour.adr=NULL; }
  1955.       }
  1956.     } else {
  1957.       retour.statuscode=-2;
  1958.       strcpybuff(retour.msg,"Timeout While Testing");
  1959.     }
  1960.     
  1961.     
  1962. #if HTS_DEBUG_CLOSESOCK
  1963.     DEBUG_W("http_test: deletehttp\n");
  1964. #endif
  1965.     deletehttp(&retour);
  1966.     retour.soc=INVALID_SOCKET;
  1967.   }
  1968.   return retour;    
  1969. }
  1970.  
  1971. // CrΘe un lien (http) vers une adresse internet iadr
  1972. // retour: structure (adresse, taille, message si erreur (si !adr))
  1973. // peut ouvrir avec des connect() non bloquants: waitconnect=0/1
  1974. int newhttp(char* _iadr,htsblk* retour,int port,int waitconnect) {  
  1975.   t_fullhostent fullhostent_buffer;    // buffer pour resolver
  1976.   T_SOC soc;                           // descipteur de la socket
  1977.   char* iadr;
  1978.   // unsigned short int port;
  1979.   
  1980.   // tester un Θventuel id:pass et virer id:pass@ si dΘtectΘ
  1981.   iadr = jump_identification(_iadr);
  1982.   
  1983.   // si iadr="#" alors c'est une fausse URL, mais un vrai fichier
  1984.   // local.
  1985.   // utile pour les tests!
  1986.   //## if (iadr[0]!=lOCAL_CHAR) {
  1987.   if (strcmp(_iadr,"file://")) {           /* non fichier */
  1988.     SOCaddr server;
  1989.     int server_size=sizeof(server);
  1990.     t_hostent* hp;    
  1991.     // effacer structure
  1992.     memset(&server, 0, sizeof(server));
  1993.  
  1994. #if HDEBUG
  1995.     printf("gethostbyname\n");
  1996. #endif
  1997.     
  1998.     // tester un Θventuel port
  1999.     if (port==-1) {
  2000.       char *a=jump_toport(iadr);
  2001. #if HTS_USEOPENSSL
  2002.       if (retour->ssl)
  2003.         port=443;
  2004.       else
  2005.         port=80;    // port par dΘfaut
  2006. #else
  2007.       port=80;    // port par dΘfaut
  2008. #endif
  2009.       if (a) {
  2010.         char iadr2[HTS_URLMAXSIZE*2];
  2011.         int i=-1;
  2012.         iadr2[0]='\0';
  2013.         sscanf(a+1,"%d",&i);
  2014.         if (i!=-1) {
  2015.           port=(unsigned short int) i;
  2016.         }
  2017.         
  2018.         // adresse vΘritable (sans :xx)
  2019.         strncatbuff(iadr2,iadr,(int) (a - iadr));
  2020.  
  2021.         // adresse sans le :xx
  2022.         hp = hts_gethostbyname(iadr2, &fullhostent_buffer);
  2023.         
  2024.       } else {
  2025.  
  2026.         // adresse normale (port par dΘfaut par la suite)
  2027.         hp = hts_gethostbyname(iadr, &fullhostent_buffer);
  2028.         
  2029.       }
  2030.       
  2031.     } else    // port dΘfini
  2032.       hp = hts_gethostbyname(iadr, &fullhostent_buffer);
  2033.  
  2034.     
  2035.     // Conversion iadr -> adresse
  2036.     // structure recevant le nom de l'h⌠te, etc
  2037.     //struct     hostent     *hp;
  2038.     if (hp == NULL) {
  2039. #if DEBUG
  2040.       printf("erreur gethostbyname\n");
  2041. #endif
  2042.       if (retour)
  2043.       if (retour->msg)
  2044.         strcpybuff(retour->msg,"Unable to get server's address");
  2045.       return INVALID_SOCKET;
  2046.     }  
  2047.     // copie adresse
  2048.     SOCaddr_copyaddr(server, server_size, hp->h_addr_list[0], hp->h_length);
  2049.     // memcpy(&SOCaddr_sinaddr(server), hp->h_addr_list[0], hp->h_length);
  2050.      
  2051.     // crΘer ("attachement") une socket (point d'accΦs) internet,en flot
  2052. #if HDEBUG
  2053.     printf("socket\n");
  2054. #endif
  2055. #if HTS_WIDE_DEBUG    
  2056.     DEBUG_W("socket\n");
  2057. #endif
  2058.     soc=socket(SOCaddr_sinfamily(server), SOCK_STREAM, 0);
  2059.     if (retour != NULL) {
  2060.       retour->debugid = HTS_STAT.stat_sockid++;
  2061.     }
  2062. #if HTS_WIDE_DEBUG    
  2063.     DEBUG_W("socket done\n");
  2064. #endif
  2065.     if (soc==INVALID_SOCKET) {
  2066.       if (retour)
  2067.       if (retour->msg)
  2068.         strcpybuff(retour->msg,"Unable to create a socket");
  2069.       return INVALID_SOCKET;                        // erreur crΘation socket impossible
  2070.     }
  2071.  
  2072.     // bind this address
  2073.     if (retour != NULL && retour->req.proxy.bindhost[0] != '\0') {
  2074.       t_fullhostent bind_buffer;
  2075.       hp = hts_gethostbyname(retour->req.proxy.bindhost, &bind_buffer);
  2076.       if (hp == NULL ||
  2077.         bind(soc, (struct sockaddr *)hp->h_addr_list[0], hp->h_length) != 0) {
  2078.         if (retour)
  2079.           if (retour->msg)
  2080.             strcpybuff(retour->msg,"Unable to bind the specificied server address");
  2081.           deletesoc(soc);
  2082.           return INVALID_SOCKET;
  2083.       }
  2084.     }
  2085.     
  2086.     // structure: connexion au domaine internet, port 80 (ou autre)
  2087.     SOCaddr_initport(server, port);
  2088. #if HDEBUG
  2089.     printf("==%d\n",soc);
  2090. #endif
  2091.  
  2092.     // connexion non bloquante?
  2093.     if (!waitconnect ) {
  2094.       unsigned long p=1;  // non bloquant
  2095. #if HTS_WIN
  2096.       ioctlsocket(soc,FIONBIO,&p);
  2097. #else
  2098.       ioctl(soc,FIONBIO,&p);
  2099. #endif
  2100.     }
  2101.     
  2102.     // Connexion au serveur lui mΩme
  2103. #if HDEBUG
  2104.     printf("connect\n");
  2105. #endif
  2106.     
  2107. #if HTS_WIDE_DEBUG
  2108.     DEBUG_W("connect\n");
  2109. #endif
  2110. #if HTS_WIN
  2111.     if (connect(soc, (const struct sockaddr FAR *)&server, server_size) != 0) {
  2112. #else
  2113.       if (connect(soc, (struct sockaddr *)&server, server_size) == -1) {
  2114. #endif
  2115.  
  2116.         // no - non blocking
  2117.         //deletesoc(soc);
  2118.         //soc=INVALID_SOCKET;
  2119.  
  2120.         // bloquant
  2121.         if (waitconnect) {
  2122. #if HDEBUG
  2123.           printf("unable to connect!\n");
  2124. #endif
  2125.           if (retour)
  2126.           if (retour->msg)
  2127.             strcpybuff(retour->msg,"Unable to connect to the server");
  2128.           /* Close the socket and notify the error!!! */
  2129.           deletesoc(soc);
  2130.           return INVALID_SOCKET;
  2131.         }
  2132.       }
  2133. #if HTS_WIDE_DEBUG    
  2134.       DEBUG_W("connect done\n");
  2135. #endif
  2136.       
  2137. #if HDEBUG
  2138.       printf("connexion Θtablie\n");
  2139. #endif
  2140.     
  2141.     // A partir de maintenant, on peut envoyer et recevoir des donnΘes
  2142.     // via le flot identifiΘ par soc (socket): write(soc,adr,taille) et 
  2143.     // read(soc,adr,taille)
  2144.  
  2145.   } else {    // on doit ouvrir un fichier local!
  2146.     // il sera gΘrΘ de la mΩme maniΦre qu'une socket (c'est idem!)
  2147.  
  2148.     soc=LOCAL_SOCKET_ID;    // pseudo-socket locale..
  2149.     // soc sera remplacΘ lors d'un http_fopen() par un handle vΘritable!
  2150.  
  2151.   }   // teste fichier local ou http
  2152.   
  2153.   return soc;
  2154. }
  2155.  
  2156.  
  2157.  
  2158. // couper http://www.truc.fr/pub/index.html -> www.truc.fr /pub/index.html
  2159. // retour=-1 si erreur.
  2160. // si file://... alors adresse=file:// (et coupe le ?query dans ce cas)
  2161. int ident_url_absolute(char* url,char* adr,char* fil) {
  2162.   int pos=0;
  2163.   int scheme=0;
  2164.  
  2165.   // effacer adr et fil
  2166.   adr[0]=fil[0]='\0';
  2167.   
  2168. #if HDEBUG
  2169.   printf("protocol: %s\n",url);
  2170. #endif
  2171.  
  2172.   // Scheme?
  2173.   {
  2174.     char* a=url;
  2175.     while (isalpha((unsigned char)*a))
  2176.       a++;
  2177.     if (*a == ':')
  2178.       scheme=1;
  2179.   }
  2180.  
  2181.   // 1. optional scheme ":"
  2182.   if ((pos=strfield(url,"file:"))) {    // fichier local!! (pour les tests)
  2183.     //!! p+=3;
  2184.     strcpybuff(adr,"file://");
  2185.   } else if ((pos=strfield(url,"http:"))) {    // HTTP
  2186.     //!!p+=3;
  2187.   } else if ((pos=strfield(url,"ftp:"))) {    // FTP
  2188.     strcpybuff(adr,"ftp://");    // FTP!!
  2189.     //!!p+=3;
  2190. #if HTS_USEOPENSSL
  2191.   } else if (SSL_is_available && (pos=strfield(url,"https:"))) {    // HTTPS
  2192.     strcpybuff(adr,"https://");
  2193. #endif
  2194.   } else if (scheme) {
  2195.     return -1;    // erreur non reconnu
  2196.   } else
  2197.     pos=0;
  2198.  
  2199.   // 2. optional "//" authority
  2200.   if (strncmp(url+pos,"//",2)==0)
  2201.     pos+=2;
  2202.  
  2203.   // (url+pos) now points to the path (not net path)
  2204.  
  2205.   //## if (adr[0]!=lOCAL_CHAR) {    // adresse normale http
  2206.   if (!strfield(adr,"file:")) {      // PAS file://
  2207.     char *p,*q;
  2208.     p=url+pos;
  2209.  
  2210.     // p pointe sur le dΘbut de l'adresse, ex: www.truc.fr/sommaire/index.html
  2211.     q=strchr(jump_identification(p),'/');
  2212.     if (q==0) q=strchr(jump_identification(p),'?');     // http://www.foo.com?bar=1
  2213.     if (q==0) q=p+strlen(p);  // pointe sur \0
  2214.     // q pointe sur le chemin, ex: index.html?query=recherche
  2215.     
  2216.     // chemin www... trop long!!
  2217.     if ( ( ((int) (q - p)) )  > HTS_URLMAXSIZE) {
  2218.       //strcpybuff(retour.msg,"Path too long");
  2219.       return -1;    // erreur
  2220.     }
  2221.     
  2222.     // recopier adresse www..
  2223.     strncatbuff(adr,p, ((int) (q - p)) );
  2224.     // *( adr+( ((int) q) - ((int) p) ) )=0;  // faut arrΩter la fumette!
  2225.     // recopier chemin /pub/..
  2226.     if (q[0] != '/')    // page par dΘfaut (/)
  2227.       strcatbuff(fil,"/");
  2228.     strcatbuff(fil,q);
  2229.     // SECURITE:
  2230.     // simplifier url pour les ../
  2231.     fil_simplifie(fil);
  2232.   } else {    // localhost file://
  2233.     char *p;
  2234.     int i;
  2235.     char* a;
  2236.  
  2237.     p=url+pos;
  2238.     if (*p == '/' || *p == '\\') {  /* file:///.. */
  2239.       strcatbuff(fil,p);    // fichier local ; adr="#"
  2240.     } else {
  2241.       strcatbuff(fil,"//");   /* file://server/foo */
  2242.       strcatbuff(fil,p);
  2243.     }
  2244.  
  2245.     a=strchr(fil,'?');
  2246.     if (a) 
  2247.       *a='\0';      /* couper query (inutile pour file:// lors de la requΩte) */
  2248.     // filtrer les \\ -> / pour les fichiers DOS
  2249.     for(i=0;i<(int) strlen(fil);i++)
  2250.       if (fil[i]=='\\')
  2251.         fil[i]='/';
  2252.   }
  2253.  
  2254.   // no hostname
  2255.   if (!strnotempty(adr))
  2256.     return -1;    // erreur non reconnu
  2257.  
  2258.   // nommer au besoin.. (non utilisΘ normalement)
  2259.   if (!strnotempty(fil))
  2260.     strcpybuff(fil,"default-index.html");
  2261.  
  2262.   // case insensitive pour adresse
  2263.   {
  2264.     char *a=jump_identification(adr);
  2265.     while(*a) {
  2266.       if ((*a>='A') && (*a<='Z'))
  2267.         *a+='a'-'A';       
  2268.       a++;
  2269.     }
  2270.   }
  2271.   
  2272.   return 0;
  2273. }
  2274.  
  2275. // simplification des ../
  2276. void fil_simplifie(char* f) {
  2277.   int i=0;
  2278.   int last=0;
  2279.   char* a;
  2280.  
  2281.   // Θliminer ../
  2282.   while (f[i]) {
  2283.     
  2284.     if (f[i]=='/') {
  2285.       if (f[i+1]=='.')
  2286.       if (f[i+2]=='.')      // couper dernier rΘpertoire
  2287.       if (f[i+3]=='/')      // Θviter les /tmp/..coolandlamedir/
  2288.       {    // couper dernier rΘpertoire
  2289.         char tempo[HTS_URLMAXSIZE*2];
  2290.         tempo[0]='\0';
  2291.         //
  2292.         if (!last)                /* can't go upper.. */
  2293.           strcpybuff(tempo,"/");
  2294.         else
  2295.           strncpy(tempo,f,last+1);
  2296.         tempo[last+1]='\0';
  2297.         strcatbuff(tempo,f+i+4);
  2298.         strcpybuff(f,tempo);    // remplacer
  2299.         i=-1;             // recommencer
  2300.         last=0;
  2301.       }
  2302.       
  2303.       if (i>=0)
  2304.         last=i;
  2305.       else
  2306.         last=0;
  2307.     }
  2308.     
  2309.     i++;
  2310.   }
  2311.  
  2312.   // Θliminer ./
  2313.   while ( (a=strstr(f,"./")) ) {
  2314.     char tempo[HTS_URLMAXSIZE*2];
  2315.     tempo[0]='\0';
  2316.     strcpybuff(tempo,a+2);
  2317.     strcpybuff(a,tempo);
  2318.   }
  2319.   // delete all remaining ../ (potential threat)
  2320.   while ( (a=strstr(f,"../")) ) {
  2321.     char tempo[HTS_URLMAXSIZE*2];
  2322.     tempo[0]='\0';
  2323.     strcpybuff(tempo,a+3);
  2324.     strcpybuff(a,tempo);
  2325.   }
  2326.   
  2327. }
  2328.  
  2329. // fermer liaison fichier ou socket
  2330. HTS_INLINE void deletehttp(htsblk* r) {
  2331. #if HTS_DEBUG_CLOSESOCK
  2332.     char info[256];
  2333.     sprintf(info,"deletehttp: (htsblk*) %d\n",r);
  2334.     DEBUG_W2(info);
  2335. #endif
  2336. #if HTS_USEOPENSSL
  2337.     /* Free OpenSSL structures */
  2338.     if (SSL_is_available && r->ssl_con) {
  2339.       SSL_shutdown(r->ssl_con);
  2340.       SSL_free(r->ssl_con);
  2341.       r->ssl_con=NULL;
  2342.     }
  2343. #endif  
  2344.   if (r->soc!=INVALID_SOCKET) {
  2345.     if (r->is_file) {
  2346.       if (r->fp)
  2347.         fclose(r->fp);
  2348.       r->fp=NULL;
  2349.     } else {
  2350.       if (r->soc!=LOCAL_SOCKET_ID)
  2351.         deletesoc_r(r);
  2352.     }
  2353.     r->soc=INVALID_SOCKET;
  2354.   }
  2355. }
  2356.  
  2357. // free the addr buffer
  2358. // always returns 1
  2359. HTS_INLINE int deleteaddr(htsblk* r) {
  2360.   if (r->adr) {
  2361.     freet(r->adr);
  2362.     r->adr = NULL;
  2363.   }
  2364.   return 1;
  2365. }
  2366.  
  2367. // fermer une socket
  2368. HTS_INLINE void deletesoc(T_SOC soc) {
  2369.   if (soc!=INVALID_SOCKET) {
  2370. // J'ai plantΘ.. pas de shutdown
  2371. //#if HTS_WIDE_DEBUG    
  2372. //    DEBUG_W("shutdown\n");
  2373. //#endif
  2374. //    shutdown(soc,2);  // shutdown
  2375. //#if HTS_WIDE_DEBUG    
  2376. //    DEBUG_W("shutdown done\n");
  2377. //#endif
  2378.     // Ne pas oublier de fermer la connexion avant de partir.. (plus propre)
  2379. #if HTS_WIDE_DEBUG    
  2380.     DEBUG_W("close\n");
  2381. #endif
  2382. #if HTS_WIN
  2383.     closesocket(soc);
  2384. #else
  2385.     close(soc);
  2386. #endif
  2387. #if HTS_WIDE_DEBUG    
  2388.     DEBUG_W("close done\n");
  2389. #endif
  2390.   }
  2391. }
  2392.  
  2393. /* Will also clean other things */
  2394. HTS_INLINE void deletesoc_r(htsblk* r) {
  2395. #if HTS_USEOPENSSL
  2396.   if (SSL_is_available && r->ssl_con) {
  2397.     SSL_shutdown(r->ssl_con);
  2398.     // SSL_CTX_set_quiet_shutdown(r->ssl_con->ctx, 1);
  2399.     SSL_free(r->ssl_con);
  2400.     r->ssl_con=NULL;
  2401.   }
  2402. #endif
  2403.   deletesoc(r->soc);
  2404.   r->soc=INVALID_SOCKET;
  2405. }
  2406.  
  2407. // renvoi le nombre de secondes depuis 1970
  2408. HTS_INLINE TStamp time_local(void) {
  2409.   return ((TStamp) time(NULL));
  2410. }
  2411.  
  2412. // number of millisec since 1970
  2413. HTSEXT_API HTS_INLINE TStamp mtime_local(void) {
  2414. #ifndef HTS_DO_NOT_USE_FTIME
  2415.   struct timeb B;
  2416.   ftime( &B );
  2417.   return (TStamp) ( ((TStamp) B.time * (TStamp) 1000)
  2418.         + ((TStamp) B.millitm) );
  2419. #else
  2420.   // not precise..
  2421.   return (TStamp) ( ((TStamp) time_local() * (TStamp) 1000)
  2422.         + ((TStamp) 0) );
  2423. #endif
  2424. }
  2425.  
  2426. // convertit un nombre de secondes en temps (chaine)
  2427. void sec2str(char *st,TStamp t) {
  2428.   int j,h,m,s;
  2429.   
  2430.   j=(int) (t/(3600*24));
  2431.   t-=((TStamp) j)*(3600*24);
  2432.   h=(int) (t/(3600));
  2433.   t-=((TStamp) h)*3600;
  2434.   m=(int) (t/60);
  2435.   t-=((TStamp) m)*60;
  2436.   s=(int) t;
  2437.   
  2438.   if (j>0)
  2439.     sprintf(st,"%d days, %d hours %d minutes %d seconds",j,h,m,s);
  2440.   else if (h>0)
  2441.     sprintf(st,"%d hours %d minutes %d seconds",h,m,s);
  2442.   else if (m>0)
  2443.     sprintf(st,"%d minutes %d seconds",m,s);
  2444.   else
  2445.     sprintf(st,"%d seconds",s);
  2446. }
  2447.  
  2448. // idem, plus court (chaine)
  2449. HTSEXT_API void qsec2str(char *st,TStamp t) {
  2450.   int j,h,m,s;
  2451.   
  2452.   j=(int) (t/(3600*24));
  2453.   t-=((TStamp) j)*(3600*24);
  2454.   h=(int) (t/(3600));
  2455.   t-=((TStamp) h)*3600;
  2456.   m=(int) (t/60);
  2457.   t-=((TStamp) m)*60;
  2458.   s=(int) t;
  2459.   
  2460.   if (j>0)
  2461.     sprintf(st,"%dd,%02dh,%02dmin%02ds",j,h,m,s);
  2462.   else if (h>0)
  2463.     sprintf(st,"%dh,%02dmin%02ds",h,m,s);
  2464.   else if (m>0)
  2465.     sprintf(st,"%dmin%02ds",m,s);
  2466.   else
  2467.     sprintf(st,"%ds",s);
  2468. }
  2469.  
  2470.  
  2471. // heure actuelle, GMT, format rfc (taille buffer 256o)
  2472. void time_gmt_rfc822(char* s) {
  2473.   time_t tt;
  2474.   struct tm* A;
  2475.   tt=time(NULL);
  2476.   A=gmtime(&tt);
  2477.   if (A==NULL)
  2478.     A=localtime(&tt);
  2479.   time_rfc822(s,A);
  2480. }
  2481.  
  2482. // heure actuelle, format rfc (taille buffer 256o)
  2483. void time_local_rfc822(char* s) {
  2484.   time_t tt;
  2485.   struct tm* A;
  2486.   tt=time(NULL);
  2487.   A=localtime(&tt);
  2488.   time_rfc822_local(s,A);
  2489. }
  2490.  
  2491. /* convertir une chaine en temps */
  2492. struct tm* convert_time_rfc822(char* s) {
  2493.   struct tm* result;
  2494.   /* */
  2495.   char months[]="jan feb mar apr may jun jul aug sep oct nov dec";
  2496.   char str[256];
  2497.   char* a;
  2498.   /* */
  2499.   int result_mm=-1;
  2500.   int result_dd=-1;
  2501.   int result_n1=-1;
  2502.   int result_n2=-1;
  2503.   int result_n3=-1;
  2504.   int result_n4=-1;
  2505.   /* */
  2506.   NOSTATIC_RESERVE(result, struct tm, 1);
  2507.  
  2508.   if ((int) strlen(s) > 200)
  2509.     return NULL;
  2510.   strcpybuff(str,s);
  2511.   hts_lowcase(str);
  2512.   /* Θliminer :,- */
  2513.   while( (a=strchr(str,'-')) ) *a=' ';
  2514.   while( (a=strchr(str,':')) ) *a=' ';
  2515.   while( (a=strchr(str,',')) ) *a=' ';
  2516.   /* tokeniser */
  2517.   a=str;
  2518.   while(*a) {
  2519.     char *first,*last;
  2520.     char tok[256];
  2521.     /* dΘcouper mot */
  2522.     while(*a==' ') a++;   /* sauter espaces */
  2523.     first=a;
  2524.     while((*a) && (*a!=' ')) a++;
  2525.     last=a;
  2526.     tok[0]='\0';
  2527.     if (first!=last) {
  2528.       char* pos;
  2529.       strncatbuff(tok,first,(int) (last - first));
  2530.       /* analyser */
  2531.       if ( (pos=strstr(months,tok)) ) {               /* month always in letters */
  2532.         result_mm=((int) (pos - months))/4;
  2533.       } else {
  2534.         int number;
  2535.         if (sscanf(tok,"%d",&number) == 1) {      /* number token */
  2536.           if (result_dd<0)                        /* day always first number */
  2537.             result_dd=number;
  2538.           else if (result_n1<0)
  2539.             result_n1=number;
  2540.           else if (result_n2<0)
  2541.             result_n2=number;
  2542.           else if (result_n3<0)
  2543.             result_n3=number;
  2544.           else if (result_n4<0)
  2545.             result_n4=number;
  2546.         }   /* sinon, bruit de fond(+1GMT for exampel) */
  2547.       }
  2548.     }
  2549.   }
  2550.   if ((result_n1>=0) && (result_mm>=0) && (result_dd>=0) && (result_n2>=0) && (result_n3>=0) && (result_n4>=0)) {
  2551.     if (result_n4>=1000) {               /* Sun Nov  6 08:49:37 1994 */
  2552.       result->tm_year=result_n4-1900;
  2553.       result->tm_hour=result_n1;
  2554.       result->tm_min=result_n2;
  2555.       result->tm_sec=max(result_n3,0);
  2556.     } else {                            /* Sun, 06 Nov 1994 08:49:37 GMT or Sunday, 06-Nov-94 08:49:37 GMT */
  2557.       result->tm_hour=result_n2;
  2558.       result->tm_min=result_n3;
  2559.       result->tm_sec=max(result_n4,0);
  2560.       if (result_n1<=50)                /* 00 means 2000 */
  2561.         result->tm_year=result_n1+100;
  2562.       else if (result_n1<1000)          /* 99 means 1999 */
  2563.         result->tm_year=result_n1;
  2564.       else                              /* 2000 */
  2565.         result->tm_year=result_n1-1900;
  2566.     }
  2567.     result->tm_isdst=0;        /* assume GMT */
  2568.     result->tm_yday=-1;        /* don't know */
  2569.     result->tm_wday=-1;        /* don't know */
  2570.     result->tm_mon=result_mm;
  2571.     result->tm_mday=result_dd;
  2572.     return result;
  2573.   }
  2574.   return NULL;
  2575. }
  2576.  
  2577. /* sets file time. -1 if error */
  2578. int set_filetime(char* file,struct tm* tm_time) {
  2579.   struct utimbuf tim;
  2580. #ifndef HTS_DO_NOT_USE_FTIME
  2581.   struct timeb B;
  2582.   B.timezone=0;
  2583.   ftime( &B );
  2584.   tim.actime=tim.modtime=mktime(tm_time) - B.timezone*60; 
  2585. #else
  2586.   // bogus time (GMT/local)..
  2587.   tim.actime=tim.modtime=mktime(tm_time); 
  2588. #endif
  2589.   return utime(file,&tim);
  2590. }
  2591.  
  2592. /* sets file time from RFC822 date+time, -1 if error*/
  2593. int set_filetime_rfc822(char* file,char* date) {
  2594.   struct tm* tm_s=convert_time_rfc822(date);
  2595.   if (tm_s) {
  2596.     return set_filetime(file,tm_s);
  2597.   } else return -1;
  2598. }
  2599.  
  2600.  
  2601. // heure au format rfc (taille buffer 256o)
  2602. HTS_INLINE void time_rfc822(char* s,struct tm * A) {
  2603.   if (A == NULL) {
  2604.     int localtime_returned_null=0;
  2605.     assert(localtime_returned_null);
  2606.   }
  2607.   strftime(s,256,"%a, %d %b %Y %H:%M:%S GMT",A);
  2608. }
  2609.  
  2610. // heure locale au format rfc (taille buffer 256o)
  2611. HTS_INLINE void time_rfc822_local(char* s,struct tm * A) {
  2612.   if (A == NULL) {
  2613.     int localtime_returned_null=0;
  2614.     assert(localtime_returned_null);
  2615.   }
  2616.   strftime(s,256,"%a, %d %b %Y %H:%M:%S",A);
  2617. }
  2618.  
  2619. // conversion en b,Kb,Mb
  2620. HTSEXT_API char* int2bytes(LLint n) {
  2621.   char** a=int2bytes2(n);
  2622.   char* buff;
  2623.   NOSTATIC_RESERVE(buff, char, 256);
  2624.  
  2625.   strcpybuff(buff,a[0]);
  2626.   strcatbuff(buff,a[1]);
  2627.   return concat(buff,"");
  2628. }
  2629.  
  2630. // conversion en b/s,Kb/s,Mb/s
  2631. HTSEXT_API char* int2bytessec(long int n) {
  2632.   char* buff;
  2633.   char** a=int2bytes2(n);
  2634.   NOSTATIC_RESERVE(buff, char, 256);
  2635.  
  2636.   strcpybuff(buff,a[0]);
  2637.   strcatbuff(buff,a[1]);
  2638.   return concat(buff,"/s");
  2639. }
  2640. HTSEXT_API char* int2char(int n) {
  2641.   char* buffer;
  2642.   NOSTATIC_RESERVE(buffer, char, 32);
  2643.   sprintf(buffer,"%d",n);
  2644.   return concat(buffer,"");
  2645. }
  2646.  
  2647. // conversion en b,Kb,Mb, nombre et type sΘparΘs
  2648. // limite: 2.10^9.10^6B
  2649.  
  2650. /* See http://physics.nist.gov/cuu/Units/binary.html */
  2651. #define ToLLint(a) ((LLint)(a))
  2652. #define ToLLintKiB (ToLLint(1024))
  2653. #define ToLLintMiB (ToLLintKiB*ToLLintKiB)
  2654. #ifdef HTS_LONGLONG
  2655. #define ToLLintGiB (ToLLintKiB*ToLLintKiB*ToLLintKiB)
  2656. #define ToLLintTiB (ToLLintKiB*ToLLintKiB*ToLLintKiB*ToLLintKiB)
  2657. #define ToLLintPiB (ToLLintKiB*ToLLintKiB*ToLLintKiB*ToLLintKiB*ToLLintKiB)
  2658. #endif
  2659. typedef struct {
  2660.   char buff1[256];
  2661.   char buff2[32];
  2662.   char* buffadr[2];
  2663. } strc_int2bytes2;
  2664. HTSEXT_API char** int2bytes2(LLint n) {
  2665.   strc_int2bytes2* strc;
  2666.   NOSTATIC_RESERVE(strc, strc_int2bytes2, 1);
  2667.  
  2668.   if (n < ToLLintKiB) {
  2669.     sprintf(strc->buff1,"%d",(int)(LLint)n);
  2670.     strcpybuff(strc->buff2,"B");
  2671.   } else if (n < ToLLintMiB) {
  2672.     sprintf(strc->buff1,"%d,%02d",(int)((LLint)(n/ToLLintKiB)),(int)((LLint)((n%ToLLintKiB)*100)/ToLLintKiB));
  2673.     strcpybuff(strc->buff2,"KiB");
  2674.   }
  2675. #ifdef HTS_LONGLONG
  2676.   else if (n < ToLLintGiB) {
  2677.     sprintf(strc->buff1,"%d,%02d",(int)((LLint)(n/(ToLLintMiB))),(int)((LLint)(((n%(ToLLintMiB))*100)/(ToLLintMiB))));
  2678.     strcpybuff(strc->buff2,"MiB");
  2679.   } else if (n < ToLLintTiB) {
  2680.     sprintf(strc->buff1,"%d,%02d",(int)((LLint)(n/(ToLLintGiB))),(int)((LLint)(((n%(ToLLintGiB))*100)/(ToLLintGiB))));
  2681.     strcpybuff(strc->buff2,"GiB");
  2682.   } else if (n < ToLLintPiB) {
  2683.     sprintf(strc->buff1,"%d,%02d",(int)((LLint)(n/(ToLLintTiB))),(int)((LLint)(((n%(ToLLintTiB))*100)/(ToLLintTiB))));
  2684.     strcpybuff(strc->buff2,"TiB");
  2685.   } else {
  2686.     sprintf(strc->buff1,"%d,%02d",(int)((LLint)(n/(ToLLintPiB))),(int)((LLint)(((n%(ToLLintPiB))*100)/(ToLLintPiB))));
  2687.     strcpybuff(strc->buff2,"PiB");
  2688.   }
  2689. #else
  2690.   else {
  2691.     sprintf(strc->buff1,"%d,%02d",(int)((LLint)(n/(ToLLintMiB))),(int)((LLint)(((n%(ToLLintMiB))*100)/(ToLLintMiB))));
  2692.     strcpybuff(strc->buff2,"MiB");
  2693.   }
  2694. #endif
  2695.   strc->buffadr[0]=strc->buff1;
  2696.   strc->buffadr[1]=strc->buff2;
  2697.   return strc->buffadr;
  2698. }
  2699.  
  2700. #if HTS_WIN
  2701. #else
  2702. // ignore sigpipe?
  2703. int sig_ignore_flag( int setflag ) {     // flag ignore
  2704.   static int flag=0;   /* YES, this one is true static */
  2705.   if (setflag>=0)
  2706.     flag=setflag;
  2707.   return flag;
  2708. }
  2709. #endif
  2710.  
  2711. // envoi de texte (en tΩtes gΘnΘralement) sur la socket soc
  2712. HTS_INLINE int sendc(htsblk* r, char* s) {
  2713.   int n, ssz = (int)strlen(s);
  2714.  
  2715. #if HTS_WIN
  2716. #else
  2717.   sig_ignore_flag(1);
  2718. #endif
  2719. #if HDEBUG
  2720.   write(0,s,ssz);
  2721. #endif
  2722.  
  2723. #if HTS_USEOPENSSL
  2724.   if (SSL_is_available && r->ssl) {
  2725.     n = SSL_write(r->ssl_con, s, ssz);
  2726.   } else
  2727. #endif
  2728.     n = send(r->soc,s,ssz,0);
  2729.  
  2730. #if HTS_WIN
  2731. #else
  2732.   sig_ignore_flag(0);
  2733. #endif
  2734.  
  2735.   return ( n == ssz ) ? n : -1;
  2736. }
  2737.  
  2738.  
  2739. // Remplace read
  2740. int finput(int fd,char* s,int max) {
  2741.   char c;
  2742.   int j=0;
  2743.   do {
  2744.     //c=fgetc(fp);
  2745.     if (read(fd,&c,1)<=0) {
  2746.       c=0;
  2747.     }
  2748.     if (c!=0) {
  2749.       switch(c) {
  2750.       case 10: c=0; break;
  2751.       case 13: break;  // sauter ces caractΦres
  2752.       default: s[j++]=c; break;
  2753.       }
  2754.     }
  2755.   }  while((c!=0) && (j<max-1));
  2756.   s[j]='\0';
  2757.   return j;
  2758.  
  2759. // Like linput, but in memory (optimized)
  2760. int binput(char* buff,char* s,int max) {
  2761.   char* end;
  2762.   int count;
  2763.  
  2764.   // clear buffer
  2765.   s[0]='\0';
  2766.   // end of buffer?
  2767.   if ( *buff == '\0')
  2768.     return 1;
  2769.   // find ending \n
  2770.   end=strchr(buff,'\n');
  2771.   // ..or end of buffer
  2772.   if (!end)
  2773.     end=buff+strlen(buff);
  2774.   // then count number of bytes, maximum=max
  2775.   count=min(max,end-buff);
  2776.   // and strip annoying ending cr
  2777.   while( (count>0) && (buff[count] == '\r'))
  2778.     count--;
  2779.   // copy
  2780.   if (count > 0) {
  2781.     strncatbuff(s, buff, count);
  2782.   }
  2783.   // and terminate with a null char
  2784.   s[count]='\0';
  2785.   // then return the supplemental jump offset
  2786.   return (end-buff)+1;
  2787.  
  2788. // Lecture d'une ligne (peut Ωtre unicode α priori)
  2789. int linput(FILE* fp,char* s,int max) {
  2790.   int c;
  2791.   int j=0;
  2792.   do {
  2793.     c=fgetc(fp);
  2794.     if (c!=EOF) {
  2795.       switch(c) {
  2796.         case 13: break;  // sauter CR
  2797.         case 10: c=-1; break;
  2798.         case 9: case 12: break;  // sauter ces caractΦres
  2799.         default: s[j++]=(char) c; break;
  2800.       }
  2801.     }
  2802.   }  while((c!=-1) && (c!=EOF) && (j<(max-1)));
  2803.   s[j]='\0';
  2804.   return j;
  2805. }
  2806. int linputsoc(T_SOC soc, char* s, int max) {
  2807.   int c;
  2808.   int j=0;
  2809.   do {
  2810.     unsigned char ch;
  2811.     if (recv(soc, &ch, 1, 0) == 1) {
  2812.       c = ch;
  2813.     } else {
  2814.       c = EOF;
  2815.     }
  2816.     if (c!=EOF) {
  2817.       switch(c) {
  2818.         case 13: break;  // sauter CR
  2819.         case 10: c=-1; break;
  2820.         case 9: case 12: break;  // sauter ces caractΦres
  2821.         default: s[j++]=(char) c; break;
  2822.       }
  2823.     }
  2824.   }  while((c!=-1) && (c!=EOF) && (j<(max-1)));
  2825.   s[j]='\0';
  2826.   return j;
  2827. }
  2828. int linputsoc_t(T_SOC soc, char* s, int max, int timeout) {
  2829.   if (check_readinput_t(soc, timeout)) {
  2830.     return linputsoc(soc, s, max);
  2831.   }
  2832.   return -1;
  2833. }
  2834. int linput_trim(FILE* fp,char* s,int max) {
  2835.   int rlen=0;
  2836.   char* ls=(char*) malloct(max+2);
  2837.   s[0]='\0';
  2838.   if (ls) {
  2839.     char* a;
  2840.     // lire ligne
  2841.     rlen=linput(fp,ls,max);
  2842.     if (rlen) {
  2843.       // sauter espaces et tabs en fin
  2844.       while( (rlen>0) && ((ls[max(rlen-1,0)]==' ') || (ls[max(rlen-1,0)]=='\t')) )
  2845.         ls[--rlen]='\0';
  2846.       // sauter espaces en dΘbut
  2847.       a=ls;
  2848.       while((rlen>0) && ((*a==' ') || (*a=='\t'))) {
  2849.         a++;
  2850.         rlen--;
  2851.       }
  2852.       if (rlen>0) {
  2853.         memcpy(s,a,rlen);      // can copy \0 chars
  2854.         s[rlen]='\0';
  2855.       }
  2856.     }
  2857.     //
  2858.     freet(ls);
  2859.   }
  2860.   return rlen;
  2861. }
  2862. int linput_cpp(FILE* fp,char* s,int max) {
  2863.   int rlen=0;
  2864.   s[0]='\0';
  2865.   do {
  2866.     int ret;
  2867.     if (rlen>0)
  2868.     if (s[rlen-1]=='\\')
  2869.       s[--rlen]='\0';      // couper \ final
  2870.     // lire ligne
  2871.     ret=linput_trim(fp,s+rlen,max-rlen);
  2872.     if (ret>0)
  2873.       rlen+=ret;
  2874.   } while((s[max(rlen-1,0)]=='\\') && (rlen<max));
  2875.   return rlen;
  2876. }
  2877.  
  2878. // idem avec les car spΘciaux
  2879. void rawlinput(FILE* fp,char* s,int max) {
  2880.   int c;
  2881.   int j=0;
  2882.   do {
  2883.     c=fgetc(fp);
  2884.     if (c!=EOF) {
  2885.       switch(c) {
  2886.         case 13: break;  // sauter CR
  2887.         case 10: c=-1; break;
  2888.         default: s[j++]=(char) c; break;
  2889.       }
  2890.     }
  2891.   }  while((c!=-1) && (c!=EOF) && (j<(max-1)));
  2892.   s[j++]='\0';
  2893. }
  2894.  
  2895.  
  2896. // compare le dΘbut de f avec s et retourne la position de la fin
  2897. // 'A=a' (case insensitive)
  2898. int strfield(const char* f,const char* s) {
  2899.   int r=0;
  2900.   while (streql(*f,*s) && ((*f)!=0) && ((*s)!=0)) { f++; s++; r++; }
  2901.   if (*s==0)
  2902.     return r;
  2903.   else
  2904.     return 0;
  2905. }
  2906.  
  2907. //cherche chaine, case insensitive
  2908. char* strstrcase(char *s,char *o) {
  2909.   while((*s) && (strfield(s,o)==0)) s++;
  2910.   if (*s=='\0') return NULL;
  2911.   return s;  
  2912. }
  2913.  
  2914.  
  2915. // Unicode detector
  2916. // See http://www.unicode.org/unicode/reports/tr28/
  2917. // (sect Table 3.1B. Legal UTF-8 Byte Sequences)
  2918. typedef struct {
  2919.   unsigned int pos;
  2920.   unsigned char data[4];
  2921. } t_auto_seq;
  2922.  
  2923. // char between a and b
  2924. #define CHAR_BETWEEN(c, a, b)       ( (c) >= 0x##a ) && ( (c) <= 0x##b )
  2925. // sequence start
  2926. #define SEQBEG                      ( inseq == 0 )
  2927. // in this block
  2928. #define BLK(n,a, b)                 ( (seq.pos >= n) && ((err = CHAR_BETWEEN(seq.data[n], a, b))) )
  2929. #define ELT(n,a)                    BLK(n,a,a)
  2930. // end
  2931. #define SEQEND                      ((ok = 1))
  2932. // sequence started, character will fail if error
  2933. #define IN_SEQ                      ( (inseq = 1) )
  2934. // decoding error
  2935. #define BAD_SEQ                     ( (ok == 0) && (inseq != 0) && (!err) )
  2936. // no sequence started
  2937. #define NO_SEQ                      ( inseq == 0 )
  2938.  
  2939. // is this block an UTF unicode textfile?
  2940. // 0 : no
  2941. // 1 : yes
  2942. // -1: don't know
  2943. int is_unicode_utf8(unsigned char* buffer, unsigned int size) {
  2944.   t_auto_seq seq;
  2945.   unsigned int i;
  2946.   int is_utf=-1;
  2947.  
  2948.   seq.pos=0;
  2949.   for(i=0 ; i < size ; i++) {
  2950.     unsigned int ok=0;
  2951.     unsigned int inseq=0;
  2952.     unsigned int err=0;
  2953.  
  2954.     seq.data[seq.pos]=buffer[i];
  2955.     /**/ if ( SEQBEG && BLK(0,00,7F) && IN_SEQ && SEQEND                                                 ) { }
  2956.     else if ( SEQBEG && BLK(0,C2,DF) && IN_SEQ && BLK(1,80,BF) && SEQEND                                 ) { }
  2957.     else if ( SEQBEG && ELT(0,E0   ) && IN_SEQ && BLK(1,A0,BF) && BLK(2,80,BF) && SEQEND                 ) { }
  2958.     else if ( SEQBEG && BLK(0,E1,EC) && IN_SEQ && BLK(1,80,BF) && BLK(2,80,BF) && SEQEND                 ) { }
  2959.     else if ( SEQBEG && ELT(0,ED   ) && IN_SEQ && BLK(1,80,9F) && BLK(2,80,BF) && SEQEND                 ) { }
  2960.     else if ( SEQBEG && BLK(0,EE,EF) && IN_SEQ && BLK(1,80,BF) && BLK(2,80,BF) && SEQEND                 ) { }
  2961.     else if ( SEQBEG && ELT(0,F0   ) && IN_SEQ && BLK(1,90,BF) && BLK(2,80,BF) && BLK(3,80,BF) && SEQEND ) { }
  2962.     else if ( SEQBEG && BLK(0,F1,F3) && IN_SEQ && BLK(1,80,BF) && BLK(2,80,BF) && BLK(3,80,BF) && SEQEND ) { }
  2963.     else if ( SEQBEG && ELT(0,F4   ) && IN_SEQ && BLK(1,80,8F) && BLK(2,80,BF) && BLK(3,80,BF) && SEQEND ) { }
  2964.     else if ( NO_SEQ ) {    // bad, unknown
  2965.       return 0;
  2966.     }
  2967.     /* */
  2968.     
  2969.     /* Error */
  2970.     if ( BAD_SEQ ) {
  2971.       return 0;
  2972.     }
  2973.  
  2974.     /* unicode character */
  2975.     if (seq.pos > 0)
  2976.       is_utf=1;
  2977.  
  2978.     /* Next */
  2979.     if (ok)
  2980.       seq.pos=0;
  2981.     else
  2982.       seq.pos++;
  2983.  
  2984.     /* Internal error */
  2985.     if (seq.pos >= 4)
  2986.       return 0;
  2987.  
  2988.   }
  2989.  
  2990.   return is_utf;
  2991. }
  2992.  
  2993. void map_characters(unsigned char* buffer, unsigned int size, unsigned int* map) {
  2994.   unsigned int i;
  2995.   memset(map, 0, sizeof(unsigned int) * 256);
  2996.   for(i = 0 ; i < size ; i++) {
  2997.     map[buffer[i]]++;
  2998.   }
  2999. }
  3000.  
  3001.  
  3002. // le fichier est-il un fichier html?
  3003. //  0 : non
  3004. //  1 : oui
  3005. // -1 : on sait pas
  3006. // -2 : on sait pas, pas d'extension
  3007. int ishtml(char* fil) {
  3008.   char *a;
  3009.  
  3010.   // patch pour les truc.html?Choix=toto
  3011.   if ( (a=strchr(fil,'?')) )  // paramΦtres?
  3012.     a--;  // pointer juste avant le ?
  3013.   else
  3014.     a=fil+strlen(fil)-1;  // pointer sur le dernier caractΦre
  3015.  
  3016.   if (*a=='/') return -1;    // rΘpertoire, on sait pas!!
  3017.   //if (*a=='/') return 1;    // ok rΘpertoire, html
  3018.  
  3019.   while ( (*a!='.') && (*a!='/')  && ( a > fil)) a--;
  3020.   if (*a=='.') {  // a une extension
  3021.     char fil_noquery[HTS_URLMAXSIZE*2];
  3022.     fil_noquery[0]='\0';
  3023.     a++;  // pointer sur extension
  3024.     strncatbuff(fil_noquery,a,HTS_URLMAXSIZE);
  3025.     a=strchr(fil_noquery,'?');
  3026.     if (a)
  3027.       *a='\0';
  3028.     return ishtml_ext(fil_noquery);     // retour
  3029.   } else return -2;   // indΘterminΘ, par exemple /truc
  3030. }
  3031.  
  3032. // idem, mais pour uniquement l'extension
  3033. int ishtml_ext(char* a) {
  3034.   int html=0;  
  3035.   //
  3036.   if (strfield2(a,"html"))       html = 1;
  3037.   else if (strfield2(a,"htm"))   html = 1;
  3038.   else if (strfield2(a,"shtml")) html = 1;
  3039.   else if (strfield2(a,"phtml")) html = 1;
  3040.   else if (strfield2(a,"htmlx")) html = 1;
  3041.   else if (strfield2(a,"shtm"))  html = 1;
  3042.   else if (strfield2(a,"phtm"))  html = 1;
  3043.   else if (strfield2(a,"htmx"))  html = 1;
  3044.   //
  3045.   // insuccΦs..
  3046.   else {
  3047.     switch(is_knowntype(a)) {
  3048.     case 1:
  3049.       html = 0;     // connu, non html
  3050.       break;
  3051.     case 2:
  3052.       html = 1;     // connu, html
  3053.       break;
  3054.     default:
  3055.       html = -1;    // inconnu..
  3056.       break;
  3057.     }
  3058.   }
  3059.   return html;  
  3060. }
  3061.  
  3062. // error (404,500..)
  3063. HTS_INLINE int ishttperror(int err) {
  3064.   switch (err/100) {
  3065.     case 4: case 5: return 1;
  3066.       break;
  3067.   }
  3068.   return 0;
  3069. }
  3070.  
  3071.  
  3072. // retourne le pointeur ou le pointeur + offset si il existe dans la chaine un @ signifiant 
  3073. // une identification
  3074. HTSEXT_API char* jump_identification(char* source) {
  3075.   char *a,*trytofind;
  3076.   // rechercher dernier @ (car parfois email transmise dans adresse!)
  3077.   // mais sauter ftp:// Θventuel
  3078.   a = jump_protocol(source);
  3079.   trytofind = strrchr_limit(a, '@', strchr(a,'/'));
  3080.   return (trytofind != NULL)?trytofind:a;
  3081. }
  3082.  
  3083. HTSEXT_API char* jump_normalized(char* source) {
  3084.   source = jump_identification(source); 
  3085.   if (strfield(source, "www") && source[3] != '\0') {
  3086.     if (source[3] == '.') {       // www.foo.com -> foo.com
  3087.       source += 4;  
  3088.     } else {                      // www-4.foo.com -> foo.com
  3089.       char* a = source + 3;
  3090.       while(*a && ( isdigit(*a) || *a == '-') ) a++;
  3091.       if (*a == '.') {
  3092.         source = a + 1;
  3093.       }
  3094.     }
  3095.   }
  3096.   return source;  
  3097. }
  3098.  
  3099. HTSEXT_API char* fil_normalized(char* source, char* dest_) {
  3100.   char* dest=dest_;
  3101.   char lastc = 0;
  3102.   int gotquery=0;
  3103.   while(*source) {
  3104.     if (*source == '?')
  3105.       gotquery=1;
  3106.     if ( 
  3107.       (!gotquery && lastc == '/' && *source == '/')  // foo//bar -> foo/bar
  3108.       ) {
  3109.     }
  3110.     else {
  3111.       *dest++ = *source;
  3112.     }
  3113.     lastc = *source;
  3114.     source++;
  3115.   }
  3116.   *dest++ = '\0';
  3117.   return dest_;
  3118. }
  3119.  
  3120. #define endwith(a) ( (len >= (sizeof(a)-1)) ? ( strncmp(dest, a+len-(sizeof(a)-1), sizeof(a)-1) == 0 ) : 0 );
  3121. HTSEXT_API char* adr_normalized(char* source, char* dest) {
  3122.   /* not yet too aggressive (no com<->net<->org checkings) */
  3123.   strcpybuff(dest, jump_normalized(source));
  3124.   return dest;
  3125. }
  3126. #undef endwith
  3127.  
  3128.  
  3129. // find port (:80) or NULL if not found
  3130. // can handle IPV6 addresses
  3131. HTSEXT_API char* jump_toport(char* source) {
  3132.   char *a,*trytofind;
  3133.   a = jump_identification(source);
  3134.   trytofind = strrchr_limit(a, ']', strchr(source, '/'));    // find last ] (http://[3ffe:b80:1234::1]:80/foo.html)
  3135.   a = strchr( (trytofind)?trytofind:a, ':');
  3136.   return a;
  3137. }
  3138.  
  3139. // strrchr, but not too far
  3140. char* strrchr_limit(char* s, char c, char* limit) {
  3141.   if (limit == NULL) {
  3142.     char* p = strrchr(s, c);
  3143.     return p?(p+1):NULL;
  3144.   } else {
  3145.     char *a=NULL, *p;
  3146.     for(;;) {
  3147.       p=strchr((a)?a:s, c);
  3148.       if ((p >= limit) || (p == NULL))
  3149.         return a;
  3150.       a=p+1;
  3151.     }
  3152.   }
  3153. }
  3154.  
  3155. // retourner adr sans ftp://
  3156. HTS_INLINE char* jump_protocol(char* source) {
  3157.   int p;
  3158.   // scheme
  3159.   // "Comparisons of scheme names MUST be case-insensitive" (RFC2616)
  3160.   if ((p=strfield(source,"http:")))
  3161.     source+=p;
  3162.   else if ((p=strfield(source,"ftp:")))
  3163.     source+=p;
  3164.   else if ((p=strfield(source,"https:")))
  3165.     source+=p;
  3166.   else if ((p=strfield(source,"file:")))
  3167.     source+=p;
  3168.   // net_path
  3169.   if (strncmp(source,"//",2)==0)
  3170.     source+=2;
  3171.   return source;
  3172. }
  3173.  
  3174. // codage base 64 a vers b
  3175. void code64(unsigned char* a,int size_a,unsigned char* b,int crlf) {
  3176.   int i1=0,i2=0,i3=0,i4=0;
  3177.   int loop=0;
  3178.   unsigned long int store;
  3179.   int n;
  3180.   const char _hts_base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  3181.   while(size_a-- > 0) {  
  3182.     // 24 bits
  3183.     n=1; 
  3184.     store = *a++;
  3185.     if (size_a-- > 0) { n=2; store <<= 8; store |= *a++; }
  3186.     if (size_a-- > 0) { n=3; store <<= 8; store |= *a++; }
  3187.     if (n==3) {
  3188.       i4=store & 63;
  3189.       i3=(store>>6) & 63;
  3190.       i2=(store>>12) & 63;
  3191.       i1=(store>>18) & 63;
  3192.     } else if (n==2) {
  3193.       store<<=2;    
  3194.       i3=store & 63;
  3195.       i2=(store>>6) & 63;
  3196.       i1=(store>>12) & 63;
  3197.     } else {
  3198.       store<<=4;
  3199.       i2=store & 63;
  3200.       i1=(store>>6) & 63;
  3201.     }
  3202.     
  3203.     *b++ = _hts_base64[i1];
  3204.     *b++ = _hts_base64[i2];
  3205.     if (n>=2)
  3206.       *b++ = _hts_base64[i3];
  3207.     else
  3208.       *b++ = '=';
  3209.     if (n>=3)
  3210.       *b++ = _hts_base64[i4];
  3211.     else
  3212.       *b++ = '=';
  3213.  
  3214.     if (crlf && ( ( loop += 3 ) % 60) == 0 ) {
  3215.       *b++ = '\r';
  3216.       *b++ = '\n';
  3217.     }
  3218.   }
  3219.   *b++='\0';
  3220. }
  3221.  
  3222. // remplacer " par " etc..
  3223. // buffer MAX 1Ko
  3224. #define strcmpbeg(a, b) strncmp(a, b, strlen(b))
  3225. HTSEXT_API void unescape_amp(char* s) {
  3226.   while(*s) {
  3227.     if (*s=='&') {
  3228.       char* end=strchr(s,';');
  3229.       if ( end && (((int) (end - s)) <= 8) ) {
  3230.         unsigned char c=0;
  3231.         
  3232.         // http://www.w3.org/TR/xhtml-modularization/dtd_module_defs.html
  3233.         if (strcmpbeg(s, "&#") == 0) {
  3234.           int num=0;
  3235.           if ( (s[2] == 'x') || (s[2] == 'X')) {
  3236.             if (sscanf(s+3, "%x", &num) == 1) {
  3237.               c=(unsigned char)num;
  3238.             }
  3239.           } else {
  3240.             if (sscanf(s+2, "%d", &num) == 1) {
  3241.               c=(unsigned char)num;
  3242.             }
  3243.           }
  3244.         } else if (strcmpbeg(s, " ")==0)
  3245.           c=32; // hack - c=160;
  3246.         else if (strcmpbeg(s, "¡")==0)
  3247.           c=161;
  3248.         else if (strcmpbeg(s, "¢")==0)
  3249.           c=162;
  3250.         else if (strcmpbeg(s, "£")==0)
  3251.           c=163;
  3252.         else if (strcmpbeg(s, "¤")==0)
  3253.           c=164;
  3254.         else if (strcmpbeg(s, "¥")==0)
  3255.           c=165;
  3256.         else if (strcmpbeg(s, "¦")==0)
  3257.           c=166;
  3258.         else if (strcmpbeg(s, "§")==0)
  3259.           c=167;
  3260.         else if (strcmpbeg(s, "¨")==0)
  3261.           c=168;
  3262.         else if (strcmpbeg(s, "©")==0)
  3263.           c=169;
  3264.         else if (strcmpbeg(s, "ª")==0)
  3265.           c=170;
  3266.         //else if (strcmpbeg(s, "«")==0)
  3267.         //  c=171;
  3268.         else if (strcmpbeg(s, "¬")==0)
  3269.           c=172;
  3270.         //else if (strcmpbeg(s, "­")==0)
  3271.         //  c=173;
  3272.         else if (strcmpbeg(s, "®")==0)
  3273.           c=174;
  3274.         else if (strcmpbeg(s, "¯")==0)
  3275.           c=175;
  3276.         else if (strcmpbeg(s, "°")==0)
  3277.           c=176;
  3278.         else if (strcmpbeg(s, "±")==0)
  3279.           c=177;
  3280.         else if (strcmpbeg(s, "²")==0)
  3281.           c=178;
  3282.         else if (strcmpbeg(s, "³")==0)
  3283.           c=179;
  3284.         else if (strcmpbeg(s, "´")==0)
  3285.           c=180;
  3286.         else if (strcmpbeg(s, "µ")==0)
  3287.           c=181;
  3288.         else if (strcmpbeg(s, "¶")==0)
  3289.           c=182;
  3290.         else if (strcmpbeg(s, "·")==0)
  3291.           c=183;
  3292.         else if (strcmpbeg(s, "¸")==0)
  3293.           c=184;
  3294.         else if (strcmpbeg(s, "¹")==0)
  3295.           c=185;
  3296.         else if (strcmpbeg(s, "º")==0)
  3297.           c=186;
  3298.         //else if (strcmpbeg(s, "»")==0)
  3299.         //  c=187;
  3300.         else if (strcmpbeg(s, "¼")==0)
  3301.           c=188;
  3302.         else if (strcmpbeg(s, "½")==0)
  3303.           c=189;
  3304.         else if (strcmpbeg(s, "¾")==0)
  3305.           c=190;
  3306.         else if (strcmpbeg(s, "¿")==0)
  3307.           c=191;
  3308.         else if (strcmpbeg(s, "À")==0)
  3309.           c=192;
  3310.         else if (strcmpbeg(s, "Á")==0)
  3311.           c=193;
  3312.         else if (strcmpbeg(s, "Â")==0)
  3313.           c=194;
  3314.         else if (strcmpbeg(s, "Ã")==0)
  3315.           c=195;
  3316.         else if (strcmpbeg(s, "Ä")==0)
  3317.           c=196;
  3318.         else if (strcmpbeg(s, "Å")==0)
  3319.           c=197;
  3320.         else if (strcmpbeg(s, "Æ")==0)
  3321.           c=198;
  3322.         else if (strcmpbeg(s, "Ç")==0)
  3323.           c=199;
  3324.         else if (strcmpbeg(s, "È")==0)
  3325.           c=200;
  3326.         else if (strcmpbeg(s, "É")==0)
  3327.           c=201;
  3328.         else if (strcmpbeg(s, "Ê")==0)
  3329.           c=202;
  3330.         else if (strcmpbeg(s, "Ë")==0)
  3331.           c=203;
  3332.         else if (strcmpbeg(s, "Ì")==0)
  3333.           c=204;
  3334.         else if (strcmpbeg(s, "Í")==0)
  3335.           c=205;
  3336.         else if (strcmpbeg(s, "Î")==0)
  3337.           c=206;
  3338.         else if (strcmpbeg(s, "Ï")==0)
  3339.           c=207;
  3340.         else if (strcmpbeg(s, "Ð")==0)
  3341.           c=208;
  3342.         else if (strcmpbeg(s, "Ñ")==0)
  3343.           c=209;
  3344.         else if (strcmpbeg(s, "Ò")==0)
  3345.           c=210;
  3346.         else if (strcmpbeg(s, "Ó")==0)
  3347.           c=211;
  3348.         else if (strcmpbeg(s, "Ô")==0)
  3349.           c=212;
  3350.         else if (strcmpbeg(s, "Õ")==0)
  3351.           c=213;
  3352.         else if (strcmpbeg(s, "Ö")==0)
  3353.           c=214;
  3354.         else if (strcmpbeg(s, "×")==0)
  3355.           c=215;
  3356.         else if (strcmpbeg(s, "Ø")==0)
  3357.           c=216;
  3358.         else if (strcmpbeg(s, "Ù")==0)
  3359.           c=217;
  3360.         else if (strcmpbeg(s, "Ú")==0)
  3361.           c=218;
  3362.         else if (strcmpbeg(s, "Û")==0)
  3363.           c=219;
  3364.         else if (strcmpbeg(s, "Ü")==0)
  3365.           c=220;
  3366.         else if (strcmpbeg(s, "Ý")==0)
  3367.           c=221;
  3368.         else if (strcmpbeg(s, "Þ")==0)
  3369.           c=222;
  3370.         else if (strcmpbeg(s, "ß")==0)
  3371.           c=223;
  3372.         else if (strcmpbeg(s, "à")==0)
  3373.           c=224;
  3374.         else if (strcmpbeg(s, "á")==0)
  3375.           c=225;
  3376.         else if (strcmpbeg(s, "â")==0)
  3377.           c=226;
  3378.         else if (strcmpbeg(s, "ã")==0)
  3379.           c=227;
  3380.         else if (strcmpbeg(s, "ä")==0)
  3381.           c=228;
  3382.         else if (strcmpbeg(s, "å")==0)
  3383.           c=229;
  3384.         else if (strcmpbeg(s, "æ")==0)
  3385.           c=230;
  3386.         else if (strcmpbeg(s, "ç")==0)
  3387.           c=231;
  3388.         else if (strcmpbeg(s, "è")==0)
  3389.           c=232;
  3390.         else if (strcmpbeg(s, "é")==0)
  3391.           c=233;
  3392.         else if (strcmpbeg(s, "ê")==0)
  3393.           c=234;
  3394.         else if (strcmpbeg(s, "ë")==0)
  3395.           c=235;
  3396.         else if (strcmpbeg(s, "ì")==0)
  3397.           c=236;
  3398.         else if (strcmpbeg(s, "í")==0)
  3399.           c=237;
  3400.         else if (strcmpbeg(s, "î")==0)
  3401.           c=238;
  3402.         else if (strcmpbeg(s, "ï")==0)
  3403.           c=239;
  3404.         else if (strcmpbeg(s, "ð")==0)
  3405.           c=240;
  3406.         else if (strcmpbeg(s, "ñ")==0)
  3407.           c=241;
  3408.         else if (strcmpbeg(s, "ò")==0)
  3409.           c=242;
  3410.         else if (strcmpbeg(s, "ó")==0)
  3411.           c=243;
  3412.         else if (strcmpbeg(s, "ô")==0)
  3413.           c=244;
  3414.         else if (strcmpbeg(s, "õ")==0)
  3415.           c=245;
  3416.         else if (strcmpbeg(s, "ö")==0)
  3417.           c=246;
  3418.         else if (strcmpbeg(s, "÷")==0)
  3419.           c=247;
  3420.         else if (strcmpbeg(s, "ø")==0)
  3421.           c=248;
  3422.         else if (strcmpbeg(s, "ù")==0)
  3423.           c=249;
  3424.         else if (strcmpbeg(s, "ú")==0)
  3425.           c=250;
  3426.         else if (strcmpbeg(s, "û")==0)
  3427.           c=251;
  3428.         else if (strcmpbeg(s, "ü")==0)
  3429.           c=252;
  3430.         else if (strcmpbeg(s, "ý")==0)
  3431.           c=253;
  3432.         else if (strcmpbeg(s, "þ")==0)
  3433.           c=254;
  3434.         else if (strcmpbeg(s, "ÿ")==0)
  3435.           c=255;
  3436.         //        
  3437.         else if (strcmpbeg(s,"&")==0)
  3438.           c='&';
  3439.         else if (strcmpbeg(s,">")==0)
  3440.           c='>';
  3441.         else if (strcmpbeg(s,"«")==0)
  3442.           c='\"';
  3443.         else if (strcmpbeg(s,"<")==0)
  3444.           c='<';
  3445.         else if (strcmpbeg(s," ")==0)
  3446.           c=' ';
  3447.         else if (strcmpbeg(s,""")==0)
  3448.           c='\"';
  3449.         else if (strcmpbeg(s,"»")==0)
  3450.           c='\"';
  3451.         else if (strcmpbeg(s,"­")==0)
  3452.           c='-';
  3453.         else if (strcmpbeg(s,"˜")==0)
  3454.           c='~';
  3455.         // remplacer?
  3456.         if (c) {
  3457.           char buff[HTS_URLMAXSIZE*2];
  3458.           buff[0]=(char) c;
  3459.           strcpybuff(buff+1,end+1);
  3460.           strcpybuff(s,buff);
  3461.         }
  3462.       }
  3463.     }
  3464.     s++;
  3465.   }
  3466. }
  3467.  
  3468. // remplacer %20 par ' ', | par : etc..
  3469. // buffer MAX 1Ko
  3470. HTSEXT_API char* unescape_http(char* s) {
  3471.   char* tempo;
  3472.   int i,j=0;
  3473.   NOSTATIC_RESERVE(tempo, char, HTS_URLMAXSIZE*2);
  3474.   for (i=0;i<(int) strlen(s);i++) {
  3475.     if (s[i]=='%') {
  3476.       i++;
  3477.       tempo[j++]=(char) ehex(s+i);
  3478.       i++;    // sauter 2 caractΦres finalement
  3479.     }
  3480.     /*
  3481.     NON a cause de trucs comme /home/0,1837,1|7|1173|Content,00.html
  3482.     else if (s[i]=='|') {                     // exemple: file:///C|Program%20Files...
  3483.       tempo[j++]=':';
  3484.     }
  3485.     */
  3486.     else
  3487.       tempo[j++]=s[i];
  3488.   }
  3489.   tempo[j++]='\0';
  3490.   return tempo;
  3491. }
  3492.  
  3493. // unescape in URL/URI ONLY what has to be escaped, to form a standard URL/URI
  3494. HTSEXT_API char* unescape_http_unharm(char* s, int no_high) {
  3495.   char* tempo;
  3496.   int i,j=0;
  3497.   NOSTATIC_RESERVE(tempo, char, HTS_URLMAXSIZE*2);
  3498.   for (i=0;i<(int) strlen(s);i++) {
  3499.     if (s[i]=='%') {
  3500.       int nchar=(char) ehex(s+i+1);
  3501.  
  3502.       int test = (  CHAR_RESERVED(nchar)
  3503.                 || CHAR_DELIM(nchar)
  3504.                 || CHAR_UNWISE(nchar)
  3505.                 || CHAR_LOW(nchar)        /* CHAR_SPECIAL */
  3506.                 || CHAR_XXAVOID(nchar) 
  3507.                 || (
  3508.                   (no_high)
  3509.                   &&
  3510.                   CHAR_HIG(nchar)
  3511.                 )
  3512.                 );
  3513.  
  3514.       if (!test) {
  3515.         tempo[j++]=(char) ehex(s+i+1);
  3516.         i+=2;
  3517.       } else {
  3518.         tempo[j++]='%';
  3519.       }
  3520.     }
  3521.     /*
  3522.     NON a cause de trucs comme /home/0,1837,1|7|1173|Content,00.html
  3523.     else if (s[i]=='|') {                     // exemple: file:///C|Program%20Files...
  3524.       tempo[j++]=':';
  3525.     }
  3526.     */
  3527.     else
  3528.       tempo[j++]=s[i];
  3529.   }
  3530.   tempo[j++]='\0';
  3531.   return tempo;
  3532. }
  3533.  
  3534. // remplacer " par %xx etc..
  3535. // buffer MAX 1Ko
  3536. HTSEXT_API void escape_spc_url(char* s) {
  3537.   x_escape_http(s,2);
  3538. }
  3539. // smith / john -> smith%20%2f%20john
  3540. HTSEXT_API void escape_in_url(char* s) {
  3541.   x_escape_http(s,1);
  3542. }
  3543. // smith / john -> smith%20/%20john
  3544. HTSEXT_API void escape_uri(char* s) {
  3545.   x_escape_http(s,3);
  3546. }
  3547. HTSEXT_API void escape_uri_utf(char* s) {
  3548.   x_escape_http(s,30);
  3549. }
  3550. HTSEXT_API void escape_check_url(char* s) {
  3551.   x_escape_http(s,0);
  3552. }
  3553. // same as escape_check_url, but returns char*
  3554. HTSEXT_API char* escape_check_url_addr(char* s) {
  3555.   char* adr;
  3556.   escape_check_url(adr = concat(s,""));
  3557.   return adr;
  3558. }
  3559.  
  3560. // strip all control characters
  3561. HTSEXT_API void escape_remove_control(char* s) {
  3562.   unsigned char* ss = (unsigned char*) s;
  3563.   while(*ss) {
  3564.     if (*ss < 32) {    /* CONTROL characters go away! */
  3565.       char tmp[HTS_URLMAXSIZE*2];
  3566.       strcpybuff(tmp, ss+1);
  3567.       strcpybuff(ss, tmp);
  3568.     } else {
  3569.       ss++;
  3570.     }
  3571.   }
  3572. }
  3573.  
  3574.  
  3575. HTSEXT_API void x_escape_http(char* s,int mode) {
  3576.   while(*s) {
  3577.     int test=0;
  3578.     if (mode == 0)
  3579.       test=(strchr("\" ",*s)!=0);
  3580.     else if (mode==1) {
  3581.       test = (  CHAR_RESERVED(*s)
  3582.              || CHAR_DELIM(*s)
  3583.              || CHAR_UNWISE(*s)
  3584.              || CHAR_SPECIAL(*s)
  3585.              || CHAR_XXAVOID(*s)
  3586.              || CHAR_MARK(*s));
  3587.     }
  3588.     else if (mode==2)
  3589.       test=(strchr(" ",*s)!=0);           // n'escaper que espace
  3590.     else if (mode==3) {                   // Θchapper que ce qui est nΘcessaire
  3591.       test = (
  3592.                 CHAR_SPECIAL(*s)
  3593.              || CHAR_XXAVOID(*s) );
  3594.     }
  3595.     else if (mode==30) {                   // Θchapper que ce qui est nΘcessaire
  3596.       test = (
  3597.                 CHAR_LOW(*s)
  3598.              || CHAR_XXAVOID(*s) );
  3599.     }
  3600.  
  3601.     if (test) {
  3602.       char buffer[HTS_URLMAXSIZE*3];
  3603.       int n;
  3604.       n=(int)(unsigned char) *s;
  3605.       strcpybuff(buffer,s+1);
  3606.       sprintf(s,"%%%02x",n);
  3607.       strcatbuff(s,buffer);
  3608.     }
  3609.     s++;
  3610.   }
  3611. }
  3612.  
  3613.  
  3614. HTS_INLINE int ehexh(char c) {
  3615.   if ((c>='0') && (c<='9')) return c-'0';
  3616.   if ((c>='a') && (c<='f')) c-=('a'-'A');
  3617.   if ((c>='A') && (c<='F')) return (c-'A'+10);
  3618.   return 0;
  3619. }
  3620.  
  3621. HTS_INLINE int ehex(char* s) {
  3622.   return 16*ehexh(*s)+ehexh(*(s+1));
  3623.  
  3624. }
  3625.  
  3626. // concat, concatΦne deux chaines et renvoi le rΘsultat
  3627. // permet d'allΘger grandement le code
  3628. // il faut savoir qu'on ne peut mettre plus de 16 concat() dans une expression
  3629. typedef struct {
  3630.   char buff[16][HTS_URLMAXSIZE*2*2];
  3631.   int rol;
  3632. } concat_strc;
  3633. char* concat(const char* a,const char* b) {
  3634.   concat_strc* strc;
  3635.   NOSTATIC_RESERVE(strc, concat_strc, 1);
  3636.   strc->rol=((strc->rol+1)%16);    // roving pointer
  3637.   strcpybuff(strc->buff[strc->rol],a);
  3638.   if (b) strcatbuff(strc->buff[strc->rol],b);
  3639.   return strc->buff[strc->rol];
  3640. }
  3641. // conversion fichier / -> antislash
  3642. #if HTS_DOSNAME
  3643. char* __fconv(char* a) {
  3644.   int i;
  3645.   for(i=0;i<(int) strlen(a);i++)
  3646.     if (a[i]=='/')  // convertir
  3647.       a[i]='\\';
  3648.   return a;
  3649. }
  3650. char* fconcat(char* a,char* b) {
  3651.   return __fconv(concat(a,b));
  3652. }
  3653. char* fconv(char* a) {
  3654.   return __fconv(concat(a,""));
  3655. }
  3656. #endif
  3657.  
  3658. /* / et \\ en / */
  3659. char* __fslash(char* a) {
  3660.   int i;
  3661.   for(i=0;i<(int) strlen(a);i++)
  3662.     if (a[i]=='\\')  // convertir
  3663.       a[i]='/';
  3664.   return a;
  3665. }
  3666. char* fslash(char* a) {
  3667.   return __fslash(concat(a,""));
  3668. }
  3669.  
  3670. // conversion minuscules, avec buffer
  3671. char* convtolower(char* a) {
  3672.   concat_strc* strc;
  3673.   NOSTATIC_RESERVE(strc, concat_strc, 1);
  3674.   strc->rol=((strc->rol+1)%16);    // roving pointer
  3675.   strcpybuff(strc->buff[strc->rol],a);
  3676.   hts_lowcase(strc->buff[strc->rol]);  // lower case
  3677.   return strc->buff[strc->rol];
  3678. }
  3679.  
  3680. // conversion en minuscules
  3681. void hts_lowcase(char* s) {
  3682.   int i;
  3683.   for(i=0;i<(int) strlen(s);i++)
  3684.     if ((s[i]>='A') && (s[i]<='Z'))
  3685.       s[i]+=('a'-'A');
  3686. }
  3687.  
  3688. // remplacer un caractΦre d'une chaεne dans une autre
  3689. HTS_INLINE void hts_replace(char *s,char from,char to) { 
  3690.   char* a;
  3691.   while ((a=strchr(s,from))!=NULL) {
  3692.     *a=to;
  3693.   }
  3694. }
  3695.  
  3696.  
  3697. // caractΦre espace, guillemets, CR, LF etc..
  3698. /* SECTION OPTIMISEE:
  3699.   #define  is_space(c) (strchr(" \"\x0d\x0a\x09'",c)!=NULL)
  3700.   #define  is_realspace(c) (strchr(" \x0d\x0a\x09\x0c",c)!=NULL)
  3701. */
  3702. /*
  3703. HTS_INLINE int is_space(char c) {
  3704.   if (c==' ')  return 1;  // spc
  3705.   if (c=='"')  return 1;  // quote
  3706.   if (c==10)   return 1;  // lf
  3707.   if (c==13)   return 1;  // cr
  3708.   if (c=='\'') return 1;  // quote
  3709.   //if (c=='`')  return 1;  // backquote      << non
  3710.   if (c==9)    return 1;  // tab
  3711.   return 0;
  3712. }
  3713. */
  3714.  
  3715. // caractΦre espace, CR, LF, TAB
  3716. /*
  3717. HTS_INLINE int is_realspace(char c) {
  3718.   if (c==' ')  return 1;  // spc
  3719.   if (c==10)   return 1;  // lf
  3720.   if (c==13)   return 1;  // cr
  3721.   if (c==9)    return 1;  // tab
  3722.   return 0;
  3723. }
  3724. */
  3725.  
  3726.  
  3727.  
  3728.  
  3729.  
  3730. // deviner type d'un fichier local..
  3731. // ex: fil="toto.gif" -> s="image/gif"
  3732. void guess_httptype(char *s,char *fil) {
  3733.   get_httptype(s,fil,1);
  3734. }
  3735. // idem
  3736. // flag: 1 si toujours renvoyer un type
  3737. void get_httptype(char *s,char *fil,int flag) {
  3738.   if (ishtml(fil)==1)
  3739.     strcpybuff(s,"text/html");
  3740.   else {
  3741.     char *a=fil+strlen(fil)-1;    
  3742.     while ( (*a!='.') && (*a!='/')  && (a>fil)) a--;
  3743.     if (*a=='.') {
  3744.       int ok=0;
  3745.       int j=0;
  3746.       a++;
  3747.       while( (!ok) && (strnotempty(hts_mime[j][1])) ) {
  3748.         if (strfield2(hts_mime[j][1],a)) {
  3749.           if (hts_mime[j][0][0]!='*') {    // Une correspondance existe
  3750.             strcpybuff(s,hts_mime[j][0]);
  3751.             ok=1;
  3752.           }
  3753.         }
  3754.         j++;
  3755.       }
  3756.       
  3757.       if (!ok) if (flag) sprintf(s,"application/%s",a);
  3758.     } else {
  3759.       if (flag) strcpybuff(s,"application/octet-stream");
  3760.     }
  3761.   }
  3762. }
  3763.  
  3764. // get type of fil (php)
  3765. // s: buffer (text/html) or NULL
  3766. // return: 1 if known by user
  3767. int get_userhttptype(int setdefs,char *s,char *ext) {
  3768.   char** buffer=NULL;
  3769.   NOSTATIC_RESERVE(buffer, char*, 1);
  3770.   if (setdefs) {
  3771.     *buffer=s;
  3772.     return 1;
  3773.   } else {
  3774.     if (s)
  3775.       s[0]='\0';
  3776.     if (!ext)
  3777.       return 0;
  3778.     if (*buffer) {
  3779.       char search[1024];
  3780.       char* detect;
  3781.       sprintf(search,"\n%s=",ext);    // php=text/html
  3782.       detect=strstr(*buffer,search);
  3783.       if (!detect) {
  3784.         sprintf(search,"\n%s\n",ext); // php\ncgi=text/html
  3785.         detect=strstr(*buffer,search);
  3786.       }
  3787.       if (detect) {
  3788.         detect=strchr(detect,'=');
  3789.         if (detect) {
  3790.           detect++;
  3791.           if (s) {
  3792.             char* a;
  3793.             a=strchr(detect,'\n');
  3794.             if (a) {
  3795.               strncatbuff(s,detect,(int) (a - detect));
  3796.             }
  3797.           }
  3798.           return 1;
  3799.         }
  3800.       }
  3801.     }
  3802.   }
  3803.   return 0;
  3804. }
  3805. // renvoyer extesion d'un type mime..
  3806. // ex: "image/gif" -> gif
  3807. void give_mimext(char *s,char *st) {   
  3808.   int ok=0;
  3809.   int j=0;
  3810.   s[0]='\0';
  3811.   while( (!ok) && (strnotempty(hts_mime[j][1])) ) {
  3812.     if (strfield2(hts_mime[j][0],st)) {
  3813.       if (hts_mime[j][1][0]!='*') {    // Une correspondance existe
  3814.         strcpybuff(s,hts_mime[j][1]);
  3815.         ok=1;
  3816.       }
  3817.     }
  3818.     j++;
  3819.   }
  3820.   // wrap "x" mimetypes, such as:
  3821.   // application/x-mp3
  3822.   // or
  3823.   // application/mp3
  3824.   if (!ok) {
  3825.     int p;
  3826.     char* a=NULL;
  3827.     if ((p=strfield(st,"application/x-")))
  3828.       a=st+p;
  3829.     else if ((p=strfield(st,"application/")))
  3830.       a=st+p;
  3831.     if (a) {
  3832.       if ((int)strlen(a) >= 1) {
  3833.         if ((int)strlen(a) <= 4) {
  3834.           strcpybuff(s,a);
  3835.           ok=1;
  3836.         }
  3837.       }
  3838.     }
  3839.   }
  3840. }
  3841. // extension connue?..
  3842. //  0 : non
  3843. //  1 : oui
  3844. //  2 : html
  3845. int is_knowntype(char *fil) {
  3846.   int j=0;
  3847.   if (!fil)
  3848.     return 0;
  3849.   while(strnotempty(hts_mime[j][1])) {
  3850.     if (strfield2(hts_mime[j][1],fil)) {
  3851.       if (strfield2(hts_mime[j][0],"text/html"))
  3852.         return 2;
  3853.       else
  3854.         return 1;
  3855.     }
  3856.     j++;
  3857.   }
  3858.  
  3859.   // Known by user?
  3860.   return (is_userknowntype(fil));
  3861. }
  3862. // extension : html,gif..
  3863. char* get_ext(char *fil) {
  3864.   char* fil_noquery;
  3865.   char *a=fil+strlen(fil)-1;    
  3866.   NOSTATIC_RESERVE(fil_noquery, char, HTS_URLMAXSIZE*2);
  3867.  
  3868.   while ( (*a!='.') && (*a!='/')  && (a>fil)) a--;
  3869.   if (*a=='.') {
  3870.     fil_noquery[0]='\0';
  3871.     a++;  // pointer sur extension
  3872.     strncatbuff(fil_noquery,a,HTS_URLMAXSIZE);
  3873.     a=strchr(fil_noquery,'?');
  3874.     if (a)
  3875.       *a='\0';
  3876.     return concat(fil_noquery,"");
  3877.   }
  3878.   else
  3879.     return "";
  3880. }
  3881. // known type?..
  3882. //  0 : no
  3883. //  1 : yes
  3884. //  2 : html
  3885. // setdefs : set mime buffer:
  3886. //   file=(char*) "asp=text/html\nphp=text/html\n"
  3887. int is_userknowntype(char *fil) {
  3888.   char mime[1024];
  3889.   if (!fil)
  3890.     return 0;
  3891.   if (!strnotempty(fil))
  3892.     return 0;
  3893.   mime[0]='\0';
  3894.   get_userhttptype(0,mime,fil);
  3895.   if (!strnotempty(mime))
  3896.     return 0;
  3897.   else if (strfield2(mime,"text/html"))
  3898.     return 2;
  3899.   else
  3900.     return 1;
  3901. }
  3902.  
  3903. // page dynamique?
  3904. // is_dyntype(get_ext("foo.asp"))
  3905. int is_dyntype(char *fil) {
  3906.   int j=0;
  3907.   if (!fil)
  3908.     return 0;
  3909.   if (!strnotempty(fil))
  3910.     return 0;
  3911.   while(strnotempty(hts_ext_dynamic[j])) {
  3912.     if (strfield2(hts_ext_dynamic[j],fil)) {
  3913.       return 1;
  3914.     }
  3915.     j++;
  3916.   }
  3917.   return 0;
  3918. }
  3919.  
  3920. // types critiques qui ne doivent pas Ωtre changΘs car renvoyΘs par des serveurs qui ne
  3921. // connaissent pas le type
  3922. int may_unknown(char* st) {
  3923.   int j=0;
  3924.   // types mΘdia
  3925.   if (may_be_hypertext_mime(st))
  3926.     return 1;
  3927.   while(strnotempty(hts_mime_keep[j])) {
  3928.     if (strfield2(hts_mime_keep[j],st)) {      // trouvΘ
  3929.       return 1;
  3930.     }
  3931.     j++;
  3932.   }    
  3933.   return 0;
  3934. }
  3935.  
  3936.  
  3937.  
  3938. // -- Utils fichiers
  3939.  
  3940. // pretty print for i/o
  3941. void fprintfio(FILE* fp,char* buff,char* prefix) {
  3942.   char nl=1;
  3943.   while(*buff) {
  3944.     switch(*buff) {
  3945.     case 13: break;
  3946.     case 10:
  3947.       fprintf(fp,"\r\n");
  3948.       nl=1;
  3949.     break;
  3950.     default:
  3951.       if (nl)
  3952.         fprintf(fp,prefix);
  3953.       nl=0;
  3954.       fputc(*buff,fp);
  3955.     }
  3956.     buff++;
  3957.   }
  3958. }
  3959.  
  3960. /* Le fichier existe-t-il? (ou est-il accessible?) */
  3961. int fexist(char* s) {
  3962.   struct stat st;
  3963.   memset(&st, 0, sizeof(st));
  3964.   if (stat(s, &st) == 0) {
  3965.     if (S_ISREG(st.st_mode)) {
  3966.       return 1;
  3967.     }
  3968.   }
  3969.   return 0;
  3970.  
  3971. /* Taille d'un fichier, -1 si n'existe pas */
  3972. /* fp->_cnt ne fonctionne pas sur toute les plate-formes :-(( */
  3973. /* Note: NOT YET READY FOR 64-bit */
  3974. INTsys fsize(char* s) {
  3975.   FILE* fp;
  3976.   if (strnotempty(s)==0)     // nom vide: erreur
  3977.     return -1;
  3978.   fp=fopen(fconv(s),"rb");
  3979.   if (fp!=NULL) {
  3980.     INTsys i;
  3981.     fseek(fp,0,SEEK_END);
  3982. #ifdef HTS_FSEEKO
  3983.     i=ftello(fp);
  3984. #else
  3985.     i=ftell(fp);
  3986. #endif
  3987.     fclose(fp);
  3988.     return i;
  3989.   } else return -1;
  3990. }
  3991.  
  3992. INTsys fpsize(FILE* fp) {
  3993.   INTsys oldpos,size;
  3994.   if (!fp)
  3995.     return -1;
  3996. #ifdef HTS_FSEEKO
  3997.   oldpos=ftello(fp);
  3998. #else
  3999.   oldpos=ftell(fp);
  4000. #endif
  4001.   fseek(fp,0,SEEK_END);
  4002. #ifdef HTS_FSEEKO
  4003.   size=ftello(fp);
  4004.   fseeko(fp,oldpos,SEEK_SET);
  4005. #else
  4006.   size=ftell(fp);
  4007.   fseek(fp,oldpos,SEEK_SET);
  4008. #endif
  4009.   return size;
  4010. }
  4011.  
  4012. /* root dir, with ending / */
  4013. typedef struct {
  4014.   char path[1024+4];
  4015.   int init;
  4016. } hts_rootdir_strc;
  4017. HTSEXT_API char* hts_rootdir(char* file) {
  4018.   static hts_rootdir_strc strc = {"", 0};
  4019.   //NOSTATIC_RESERVE(strc, hts_rootdir_strc, 1);
  4020.   if (file) {
  4021.     if (!strc.init) {
  4022.       strc.path[0]='\0';
  4023.       strc.init=1;
  4024.       if (strnotempty(file)) {
  4025.         char* a;
  4026.         strcpybuff(strc.path,file);
  4027.         while((a=strrchr(strc.path,'\\'))) *a='/';
  4028.         if ((a=strrchr(strc.path,'/'))) {
  4029.           *(a+1)='\0';
  4030.         } else
  4031.           strc.path[0]='\0';
  4032.       }
  4033.       if (!strnotempty(strc.path)) {
  4034.         if( getcwd( strc.path, 1024 ) == NULL )
  4035.             strc.path[0]='\0';
  4036.         else
  4037.           strcatbuff(strc.path,"/");
  4038.       }
  4039.     }
  4040.     return NULL;
  4041.   } else if (strc.init)
  4042.     return strc.path;
  4043.   else
  4044.     return "";
  4045. }
  4046.  
  4047.  
  4048.  
  4049. HTSEXT_API hts_stat_struct HTS_STAT;
  4050. //
  4051. // return  number of downloadable bytes, depending on rate limiter
  4052. // see engine_stats() routine, too
  4053. // this routine works quite well for big files and regular ones, but apparently the rate limiter has
  4054. // some problems with very small files (rate too high)
  4055. LLint check_downloadable_bytes(int rate) {
  4056.   if (rate>0) {
  4057.     TStamp time_now;
  4058.     TStamp elapsed_useconds;
  4059.     LLint bytes_transfered_during_period;
  4060.     LLint left;
  4061.  
  4062.     // get the older timer
  4063.     int id_timer = (HTS_STAT.istat_idlasttimer + 1) % 2;
  4064.  
  4065.     time_now=mtime_local();
  4066.     elapsed_useconds = time_now - HTS_STAT.istat_timestart[id_timer];
  4067.     // NO totally stupid - elapsed_useconds+=1000;      // for the next second, too
  4068.     bytes_transfered_during_period = (HTS_STAT.HTS_TOTAL_RECV-HTS_STAT.istat_bytes[id_timer]);
  4069.     
  4070.     left = ((rate * elapsed_useconds)/1000) - bytes_transfered_during_period;
  4071.     if (left <= 0)
  4072.       left = 0;
  4073.     
  4074.     return left;
  4075.   } else
  4076.     return TAILLE_BUFFER;
  4077. }
  4078.  
  4079. //
  4080. // 0 : OK
  4081. // 1 : slow down
  4082. #if 0
  4083. int HTS_TOTAL_RECV_CHECK(int var) {
  4084.   if (HTS_STAT.HTS_TOTAL_RECV_STATE)
  4085.     return 1;
  4086.     /*
  4087.     {
  4088.     if (HTS_STAT.HTS_TOTAL_RECV_STATE==3) { 
  4089.       var = min(var,32); 
  4090.       Sleep(250); 
  4091.     } else if (HTS_STAT.HTS_TOTAL_RECV_STATE==2) { 
  4092.       var = min(var,256); 
  4093.       Sleep(100); 
  4094.     } else { 
  4095.       var/=2; 
  4096.       if (var<=0) var=1; 
  4097.       Sleep(50); 
  4098.     } 
  4099.   }
  4100.     */
  4101.   return 0;
  4102. }
  4103. #endif
  4104.  
  4105. // Lecture dans buff de size octets au maximum en utilisant la socket r (structure htsblk)
  4106. // >0 : data received
  4107. // == 0 : not yet data
  4108. // <0 : no more data or error
  4109. HTS_INLINE int hts_read(htsblk* r,char* buff,int size) {
  4110.   int retour;
  4111.   //  return read(soc,buff,size);
  4112.   if (r->is_file) {
  4113. #if HTS_WIDE_DEBUG    
  4114.     DEBUG_W("read\n");
  4115. #endif
  4116.     if (r->fp)
  4117.       retour=(int)fread(buff,1,size,r->fp);
  4118.     else
  4119.       retour=-1;
  4120.   } else {
  4121. #if HTS_WIDE_DEBUG    
  4122.     DEBUG_W("recv\n");
  4123.     if (r->soc==INVALID_SOCKET)
  4124.       printf("!!WIDE_DEBUG ERROR, soc==INVALID hts_read\n");
  4125. #endif
  4126.     //HTS_TOTAL_RECV_CHECK(size);         // Diminuer au besoin si trop de donnΘes reτues
  4127. #if HTS_USEOPENSSL
  4128.     if (SSL_is_available && r->ssl) {
  4129.       retour = SSL_read(r->ssl_con, buff, size);
  4130.       if (retour <= 0) {
  4131.         int err_code = SSL_get_error(r->ssl_con, retour);
  4132.         if (
  4133.           (err_code == SSL_ERROR_WANT_READ)
  4134.           ||
  4135.           (err_code == SSL_ERROR_WANT_WRITE)
  4136.           ) 
  4137.         {
  4138.           retour = 0;             /* no data yet (ssl cache) */
  4139.         } else {
  4140.           retour = -1;            /* eof or error */
  4141.         }
  4142.       }
  4143.     } else {
  4144. #endif
  4145.     retour=recv(r->soc,buff,size,0);
  4146.   }
  4147.   if (retour > 0)    // compter flux entrant
  4148.     HTS_STAT.HTS_TOTAL_RECV+=retour;
  4149. #if HTS_USEOPENSSL
  4150.   }
  4151. #endif
  4152. #if HTS_WIDE_DEBUG    
  4153.   DEBUG_W("recv/read done\n");
  4154. #endif
  4155.   return retour;
  4156. }
  4157.  
  4158.  
  4159. // -- Gestion cache DNS --
  4160. // 'RX98
  4161. #if HTS_DNSCACHE
  4162.  
  4163. // 'capsule' contenant uniquement le cache
  4164. t_dnscache* _hts_cache(void) {
  4165.   t_dnscache* cache;
  4166.   NOSTATIC_RESERVE(cache, t_dnscache, 1);
  4167.   return cache;
  4168. }
  4169. // free the cache
  4170. static void hts_cache_free_(t_dnscache* cache) {
  4171.   if (cache != NULL) {
  4172.     if (cache->n != NULL) {
  4173.       hts_cache_free_(cache->n);
  4174.     }
  4175.     freet(cache);
  4176.   }
  4177. }
  4178. void hts_cache_free(t_dnscache* cache) {
  4179.   if (cache != NULL) {
  4180.     hts_cache_free_(cache->n);
  4181.     cache->n = NULL;
  4182.   }
  4183. }
  4184.  
  4185. // lock le cache dns pour tout opΘration d'ajout
  4186. // plus prudent quand plusieurs threads peuvent Θcrire dedans..
  4187. // -1: status? 0: libΘrer 1:locker
  4188.  
  4189. /* 
  4190.   Simple lock function for cache
  4191.  
  4192.   Return value: always 0
  4193.   Parameter:
  4194.   1 wait for lock (mutex) available and lock it
  4195.   0 unlock the mutex
  4196.   [-1 check if locked (always return 0 with mutex)]
  4197.   -999 initialize
  4198. */
  4199. #if USE_BEGINTHREAD
  4200. int _hts_lockdns(int i) {
  4201.   static PTHREAD_LOCK_TYPE hMutex; 
  4202.   return htsSetLock(&hMutex,i);
  4203. }
  4204. #else
  4205. int _hts_lockdns(int i) {
  4206.   int l=0;
  4207.   if (i>=0)
  4208.     l=i;
  4209.   return l;
  4210. }
  4211. #endif
  4212.  
  4213. // routine pour le cache - retour optionnel α donner α chaque fois
  4214. // NULL: nom non encore testΘ dans le cache
  4215. // si h_length==0 alors le nom n'existe pas dans le dns
  4216. t_hostent* _hts_ghbn(t_dnscache* cache,char* iadr,t_hostent* retour) {
  4217.   // attendre que le cache dns soit prΩt
  4218.   while(_hts_lockdns(-1));  // attendre libΘration
  4219.   _hts_lockdns(1);          // locker
  4220.  
  4221.   while(1) {
  4222.     if (strcmp(cache->iadr,iadr)==0) {  // ok trouvΘ
  4223.       if (cache->host_length>0) {  // entrΘe valide
  4224.         if (retour->h_addr_list[0])
  4225.           memcpy(retour->h_addr_list[0], cache->host_addr, cache->host_length);
  4226.         retour->h_length=cache->host_length;
  4227.       } else if (cache->host_length==0) {  // en cours
  4228.         _hts_lockdns(0);          // dΘlocker
  4229.         return NULL;
  4230.       } else {                    // erreur dans le dns, dΘja vΘrifiΘ
  4231.         if (retour->h_addr_list[0])
  4232.           retour->h_addr_list[0][0]='\0';
  4233.         retour->h_length=0;  // erreur, n'existe pas
  4234.       }
  4235.       _hts_lockdns(0);          // dΘlocker
  4236.       return retour;
  4237.     } else {    // on a pas encore trouvΘ
  4238.       if (cache->n!=NULL) { // chercher encore
  4239.         cache=cache->n;   // suivant!
  4240.       } else {
  4241.         _hts_lockdns(0);          // dΘlocker
  4242.         return NULL;    // non prΘsent        
  4243.       }
  4244.     }    
  4245.   }
  4246. }
  4247.  
  4248. // tester si iadr a dΘja ΘtΘ testΘ (ou en cours de test)
  4249. // 0 non encore
  4250. // 1 ok
  4251. // 2 non prΘsent
  4252. int hts_dnstest(char* _iadr) {
  4253.   char* iadr;
  4254.   t_dnscache* cache=_hts_cache();  // adresse du cache 
  4255.   NOSTATIC_RESERVE(iadr, char, HTS_URLMAXSIZE*2);
  4256.  
  4257.   // sauter user:pass@ Θventuel
  4258.   strcpybuff(iadr,jump_identification(_iadr));
  4259.   // couper Θventuel :
  4260.   {
  4261.     char *a;
  4262.     if ( (a=jump_toport(iadr)) )
  4263.       *a='\0';
  4264.   }
  4265.  
  4266. #if HTS_WIN
  4267.   if (inet_addr(iadr)!=INADDR_NONE)  // numΘrique
  4268. #else
  4269.   if (inet_addr(iadr)!=(in_addr_t) -1 )  // numΘrique
  4270. #endif
  4271.     return 1;
  4272.  
  4273.   while(_hts_lockdns(-1));  // attendre libΘration
  4274.   _hts_lockdns(1);          // locker
  4275.   while(1) {
  4276.     if (strcmp(cache->iadr,iadr)==0) {  // ok trouvΘ
  4277.       _hts_lockdns(0);          // dΘlocker
  4278.       return 1;    // prΘsent!
  4279.     } else {    // on a pas encore trouvΘ
  4280.       if (cache->n!=NULL) { // chercher encore
  4281.         cache=cache->n;   // suivant!
  4282.       } else {
  4283.         _hts_lockdns(0);          // dΘlocker
  4284.         return 2;    // non prΘsent        
  4285.       }
  4286.     }    
  4287.   }
  4288. }
  4289.  
  4290.  
  4291. HTSEXT_API t_hostent* vxgethostbyname(char* hostname, void* v_buffer) {
  4292.   t_fullhostent* buffer = (t_fullhostent*) v_buffer;
  4293.   /* Clear */
  4294.   fullhostent_init(buffer);
  4295.  
  4296.   /* Protection */
  4297.   if (!strnotempty(hostname)) {
  4298.     return NULL;
  4299.   }
  4300.  
  4301.   /* 
  4302.     Strip [] if any : [3ffe:b80:1234:1::1] 
  4303.     The resolver doesn't seem to handle IP6 addresses in brackets
  4304.   */
  4305.   if ((hostname[0] == '[') && (hostname[strlen(hostname)-1] == ']')) {
  4306.     char tempo[HTS_URLMAXSIZE*2];
  4307.     tempo[0]='\0';
  4308.     strncatbuff(tempo, hostname+1, strlen(hostname)-2);
  4309.     strcpybuff(hostname, tempo);
  4310.   }
  4311.  
  4312.   {
  4313. #if HTS_INET6==0
  4314.   /*
  4315.   ipV4 resolver
  4316.     */
  4317.     t_hostent* hp=gethostbyname(hostname);
  4318.     if (hp!=NULL) {
  4319.       if ( (hp->h_length) && ( ((unsigned int) hp->h_length) <= buffer->addr_maxlen) ) {
  4320.         memcpy(buffer->hp.h_addr_list[0], hp->h_addr_list[0], hp->h_length);
  4321.         buffer->hp.h_length = hp->h_length;
  4322.         return &(buffer->hp);
  4323.       }
  4324.     }
  4325. #else
  4326.     /*
  4327.     ipV6 resolver
  4328.     */
  4329.     /*
  4330.     int error_num=0;
  4331.     t_hostent* hp=getipnodebyname(hostname, AF_INET6, AI_DEFAULT, &error_num);
  4332.     oops, deprecated :(
  4333.     */
  4334.     struct addrinfo* res = NULL;
  4335.     struct addrinfo hints;
  4336.     memset(&hints, 0, sizeof(hints));
  4337.     if (IPV6_resolver == 1)        // V4 only (for bogus V6 entries)
  4338.       hints.ai_family = PF_INET;
  4339.     else if (IPV6_resolver == 2)   // V6 only (for testing V6 only)
  4340.       hints.ai_family = PF_INET6;
  4341.     else                           // V4 + V6
  4342.       hints.ai_family = PF_UNSPEC;
  4343.     hints.ai_socktype = SOCK_STREAM;
  4344.     hints.ai_protocol = IPPROTO_TCP;
  4345.     if (getaddrinfo(hostname, NULL, &hints, &res) == 0) {
  4346.       if (res) {
  4347.         if ( (res->ai_addr) && (res->ai_addrlen) && (res->ai_addrlen <= buffer->addr_maxlen) ) {
  4348.           memcpy(buffer->hp.h_addr_list[0], res->ai_addr, res->ai_addrlen);
  4349.           buffer->hp.h_length = res->ai_addrlen;
  4350.           freeaddrinfo(res);
  4351.           return &(buffer->hp);
  4352.         }
  4353.       }
  4354.     }
  4355.     if (res) {
  4356.       freeaddrinfo(res);
  4357.     }
  4358.     
  4359. #endif
  4360.   }
  4361.   return NULL;
  4362. }
  4363.  
  4364. // cache dns interne α HTS // ** FREE A FAIRE sur la chaine
  4365. t_hostent* hts_gethostbyname(char* _iadr, void* v_buffer) {
  4366.   char iadr[HTS_URLMAXSIZE*2];
  4367.   t_fullhostent* buffer = (t_fullhostent*) v_buffer;
  4368.   t_dnscache* cache=_hts_cache();  // adresse du cache
  4369.   t_hostent* hp;
  4370.  
  4371.   /* Clear */
  4372.   fullhostent_init(buffer);
  4373.  
  4374.   strcpybuff(iadr,jump_identification(_iadr));
  4375.   // couper Θventuel :
  4376.   {
  4377.     char *a;
  4378.     if ( (a=jump_toport(iadr)) )
  4379.       *a='\0';
  4380.   }
  4381.  
  4382.   // effacer structure de retour, crΘer nouvelle
  4383.   /*
  4384.   memset(&host, 0, sizeof(t_hostent));  
  4385.   host.h_addr_list=he;
  4386.   he[0]=NULL;
  4387.   he[1]=NULL;  
  4388.   host.h_length=0;  
  4389.   */
  4390.   cache->iadr[0]='*';
  4391.   cache->iadr[1]='\0';
  4392.   
  4393.   /* get IP from the dns cache */
  4394.   hp = _hts_ghbn(cache, iadr, &buffer->hp);
  4395.   if (hp) {
  4396.     if (hp->h_length>0)
  4397.       return hp;
  4398.     else
  4399.       return NULL;    // entrΘe erronΘe (erreur DNS) dans le DNS
  4400.   } else {  // non prΘsent dans le cache dns, tester
  4401.     t_dnscache* c=cache;
  4402.     while(c->n) c=c->n;    // calculer queue
  4403.     
  4404. #if HTS_WIDE_DEBUG    
  4405.     DEBUG_W("gethostbyname\n");
  4406. #endif      
  4407. #if HDEBUG
  4408.     printf("gethostbyname (not in cache)\n");
  4409. #endif
  4410.     {
  4411.       unsigned long inetaddr;
  4412. #if HTS_WIN
  4413.       if ((inetaddr=inet_addr(iadr))==INADDR_NONE) {
  4414. #else
  4415.       if ((inetaddr=inet_addr(iadr))==(in_addr_t) -1 ) {
  4416. #endif        
  4417. #if DEBUGDNS 
  4418.         printf("resolving (not cached) %s\n",iadr);
  4419. #endif
  4420.         hp=vxgethostbyname(iadr, buffer);  // calculer IP host
  4421.       } else {     // numΘrique, convertir sans passer par le dns
  4422.         buffer->hp.h_addr_list[0]=(char*) &inetaddr;
  4423.         buffer->hp.h_length=4;
  4424.         hp=&buffer->hp;
  4425.       }
  4426.     }
  4427. #if HTS_WIDE_DEBUG    
  4428.     DEBUG_W("gethostbyname done\n");
  4429. #endif
  4430.     cache->n=(t_dnscache*) calloct(1,sizeof(t_dnscache));
  4431.     if (cache->n!=NULL) {
  4432.       strcpybuff(cache->n->iadr,iadr);
  4433.       if (hp!=NULL) {
  4434.         memcpy(cache->n->host_addr, hp->h_addr_list[0], hp->h_length);
  4435.         cache->n->host_length=hp->h_length;
  4436.       } else {
  4437.         cache->n->host_addr[0]='\0';
  4438.         cache->n->host_length=0;  // non existant dans le dns
  4439.       }
  4440.       cache->n->n=NULL;
  4441.       return hp;
  4442.     } else {  // on peut pas noter, mais on peut renvoyer le rΘsultat
  4443.       return hp;
  4444.     }        
  4445.   }  // retour hp du cache
  4446. }
  4447.  
  4448. #else
  4449. HTS_INLINE t_hostent* hts_gethostbyname(char* iadr, t_fullhostent* buffer) {
  4450.   t_hostent* retour;
  4451. #if HTS_WIDE_DEBUG    
  4452.   DEBUG_W("gethostbyname (2)\n");
  4453. #endif
  4454. #if DEBUGDNS 
  4455.     printf("blocking method gethostbyname() in progress for %s\n",iadr);
  4456. #endif
  4457.   retour=vxgethostbyname(jump_identification(iadr), );
  4458. #if HTS_WIDE_DEBUG    
  4459.   DEBUG_W("gethostbyname (2) done\n");
  4460. #endif
  4461.   return retour;
  4462. }
  4463. #endif
  4464.  
  4465.  
  4466. // --- Tracage des mallocs() ---
  4467. #ifdef HTS_TRACE_MALLOC
  4468. //#define htsLocker(A, N) htsLocker(A, N)
  4469. #define htsLocker(A, N) do {} while(0)
  4470. static mlink trmalloc = {NULL,0,0,NULL};
  4471. static int trmalloc_id=0;
  4472. static PTHREAD_LOCK_TYPE* mallocMutex = NULL;
  4473. static void hts_meminit(void) {
  4474.   //if (mallocMutex == NULL) {
  4475.   //  mallocMutex = calloc(sizeof(*mallocMutex), 1);
  4476.   //  htsLocker(mallocMutex, -999);
  4477.   //}
  4478. }
  4479. void* hts_malloc(size_t len) {
  4480.   void* adr;
  4481.   hts_meminit();
  4482.   htsLocker(mallocMutex, 1);
  4483.   fassert(len > 0);
  4484.   adr = hts_xmalloc(len, 0);
  4485.   htsLocker(mallocMutex, 0);
  4486.   return adr;
  4487. }
  4488. void* hts_calloc(size_t len,size_t len2) {
  4489.   void* adr;
  4490.   hts_meminit();
  4491.   fassert(len > 0);
  4492.   fassert(len2 > 0);
  4493.   htsLocker(mallocMutex, 1);
  4494.   adr = hts_xmalloc(len, len2);
  4495.   htsLocker(mallocMutex, 0);
  4496.   memset(adr, 0, len * len2);
  4497.   return adr;
  4498. }
  4499. void* hts_xmalloc(size_t len,size_t len2) {
  4500.   mlink* lnk = (mlink*) calloc(1,sizeof(mlink));
  4501.   fassert(lnk != NULL);
  4502.   fassert(len > 0);
  4503.   fassert(len2 >= 0);
  4504.   if (lnk) {
  4505.     void*  r   = NULL;
  4506.     int size, bsize = sizeof(t_htsboundary);
  4507.     if (len2)
  4508.       size = len * len2;
  4509.     else
  4510.       size = len;
  4511.     size += ((bsize - (size % bsize)) % bsize);  /* check alignement */
  4512.     r = malloc(size + bsize*2);
  4513.     fassert(r != NULL);
  4514.     if (r) {
  4515.       * ( (t_htsboundary*) ((char*) r ) ) 
  4516.         = * ( (t_htsboundary*) ( (char*) r + size + bsize ) )
  4517.         = htsboundary;
  4518.       ((char*) r) += bsize;    /* boundary */
  4519.       lnk->adr = r;
  4520.       lnk->len = size;
  4521.       lnk->id = trmalloc_id++;
  4522.       lnk->next = trmalloc.next;
  4523.       trmalloc.next = lnk;
  4524.       return r;
  4525.     } else {
  4526.       free(lnk);
  4527.     }
  4528.   }
  4529.   return NULL;
  4530. }
  4531. void hts_free(void* adr) {
  4532.   mlink* lnk = &trmalloc;
  4533.   int bsize = sizeof(t_htsboundary);
  4534.   fassert(adr != NULL);
  4535.   if (!adr) {
  4536.     return;
  4537.   }
  4538.   htsLocker(mallocMutex, 1);
  4539.   while(lnk->next != NULL) {
  4540.     if (lnk->next->adr == adr) {
  4541.       mlink* blk_free=lnk->next;
  4542.       fassert(blk_free->id != -1);
  4543.       fassert( * ( (t_htsboundary*) ( (char*) adr - bsize ) ) == htsboundary );
  4544.       fassert( * ( (t_htsboundary*) ( (char*) adr + blk_free->len ) ) == htsboundary );
  4545.       lnk->next=lnk->next->next;
  4546.       free((void*) blk_free);
  4547.       //blk_free->id=-1;
  4548.       free((char*) adr - bsize);
  4549.       htsLocker(mallocMutex, 0);
  4550.       return;
  4551.     }
  4552.     lnk = lnk->next;
  4553.     fassert(lnk->next != NULL);
  4554.   }
  4555.   free(adr);
  4556.   htsLocker(mallocMutex, 0);
  4557. }
  4558. void* hts_realloc(void* adr,size_t len) {
  4559.   int bsize = sizeof(t_htsboundary);
  4560.   len += ((bsize - (len % bsize)) % bsize);  /* check alignement */
  4561.   if (adr != NULL) {
  4562.     mlink* lnk = &trmalloc;
  4563.     htsLocker(mallocMutex, 1);
  4564.     while(lnk->next != NULL)  {
  4565.       if (lnk->next->adr==adr) {
  4566.         {
  4567.           mlink* blk_free=lnk->next;
  4568.           fassert(blk_free->id != -1);
  4569.           fassert( * ( (t_htsboundary*) ( (char*) adr - bsize ) ) == htsboundary );
  4570.           fassert( * ( (t_htsboundary*) ( (char*) adr + blk_free->len ) ) == htsboundary );
  4571.         }
  4572.         adr = realloc((char*) adr - bsize, len + bsize * 2);
  4573.         fassert(adr != NULL);
  4574.         lnk->next->adr = (char*) adr + bsize;
  4575.         lnk->next->len = len;
  4576.         * ( (t_htsboundary*) ( (char*) adr ) ) 
  4577.           = * ( (t_htsboundary*) ( (char*) adr + len + bsize) ) 
  4578.           = htsboundary;
  4579.         htsLocker(mallocMutex, 0);
  4580.         return (char*) adr + bsize;
  4581.       }
  4582.       lnk = lnk->next;
  4583.       fassert(lnk->next != NULL);
  4584.     }
  4585.     htsLocker(mallocMutex, 0);
  4586.   }
  4587.   return hts_malloc(len);
  4588. }
  4589. mlink* hts_find(char* adr) {
  4590.   char* stkframe = (char*) &stkframe;
  4591.   mlink* lnk = &trmalloc;
  4592.   int bsize = sizeof(t_htsboundary);
  4593.   fassert(adr != NULL);
  4594.   if (!adr) {
  4595.     return NULL;
  4596.   }
  4597.   htsLocker(mallocMutex, 1);
  4598.   while(lnk->next != NULL) {
  4599.     if (adr >= lnk->next->adr && adr <= lnk->next->adr + lnk->next->len) {   /* found */
  4600.       htsLocker(mallocMutex, 0);
  4601.       return lnk->next;
  4602.     }
  4603.     lnk = lnk->next;
  4604.   }
  4605.   htsLocker(mallocMutex, 0);
  4606.   {
  4607.     int depl = (int) (adr - stkframe);
  4608.     if (depl < 0) depl = -depl;
  4609.     //fassert(depl < 512000);   /* near the stack frame.. doesn't look like malloc but stack variable */
  4610.     return NULL;
  4611.   }
  4612. }
  4613. // check the malloct() and calloct() trace stack
  4614. void  hts_freeall(void) {
  4615.   int bsize = sizeof(t_htsboundary);
  4616.   while(trmalloc.next) {
  4617. #if MEMDEBUG
  4618.     printf("* block %d\t not released: at %d\t (%d\t bytes)\n",trmalloc.next->id,trmalloc.next->adr,trmalloc.next->len);
  4619. #endif
  4620.     if (trmalloc.next->id != -1) {
  4621.       free((char*) trmalloc.next->adr - bsize);
  4622.     }
  4623.   }
  4624. }
  4625. #endif
  4626.  
  4627.  
  4628. // -- divers //
  4629.  
  4630. // cut path and project name
  4631. // patch also initial path
  4632. void cut_path(char* fullpath,char* path,char* pname) {
  4633.   path[0]=pname[0]='\0';
  4634.   if (strnotempty(fullpath)) {
  4635.     if ((fullpath[strlen(fullpath)-1]=='/') || (fullpath[strlen(fullpath)-1]=='\\'))
  4636.       fullpath[strlen(fullpath)-1]='\0';
  4637.     if (strlen(fullpath)>1) {
  4638.       char* a;
  4639.       while( (a=strchr(fullpath,'\\')) ) *a='/';     // remplacer par /
  4640.       a=fullpath+strlen(fullpath)-2;
  4641.       while( (*a!='/') && ( a > fullpath)) a--;
  4642.       if (*a=='/') a++;
  4643.       strcpybuff(pname,a);
  4644.       strncatbuff(path,fullpath,(int) (a - fullpath));
  4645.     }
  4646.   }
  4647. }
  4648.  
  4649.  
  4650.  
  4651. // -- Gestion protocole ftp --
  4652.  
  4653. #if HTS_WIN
  4654. int ftp_available(void) {
  4655.   return 1;
  4656. }
  4657. #else
  4658. int ftp_available(void) {
  4659.   return 1;   // ok!
  4660.   //return 0;   // SOUS UNIX, PROBLEMES
  4661. }
  4662. #endif
  4663.  
  4664.  
  4665.  
  4666. HTSEXT_API int hts_init(void) {
  4667.   static int hts_init_ok = 0;
  4668.  
  4669.   /* Ensure external modules are loaded */
  4670.   htspe_init();
  4671.  
  4672.   if (!hts_init_ok) {
  4673.     hts_init_ok = 1;
  4674.     // default wrappers
  4675.     htswrap_init();
  4676.     htswrap_add("init",htsdefault_init);
  4677.     htswrap_add("free",htsdefault_uninit);
  4678.     htswrap_add("start",htsdefault_start);
  4679.     htswrap_add("change-options",htsdefault_chopt);
  4680.     htswrap_add("end",htsdefault_end);
  4681.     htswrap_add("check-html",htsdefault_checkhtml);
  4682.     htswrap_add("loop",htsdefault_loop);
  4683.     htswrap_add("query",htsdefault_query);
  4684.     htswrap_add("query2",htsdefault_query2);
  4685.     htswrap_add("query3",htsdefault_query3);
  4686.     htswrap_add("check-link",htsdefault_check);
  4687.     htswrap_add("pause",htsdefault_pause);
  4688.     htswrap_add("save-file",htsdefault_filesave);
  4689.     htswrap_add("link-detected",htsdefault_linkdetected);
  4690.     htswrap_add("transfer-status",htsdefault_xfrstatus);
  4691.     htswrap_add("save-name",htsdefault_savename);
  4692.   }
  4693.   
  4694. #if HTS_USEOPENSSL
  4695.   /*
  4696.   Initialize the OpensSSL library
  4697.   */
  4698.   if (!openssl_ctx && SSL_is_available) {
  4699.     if (SSL_load_error_strings) SSL_load_error_strings();
  4700.     SSL_library_init();
  4701.     ///if (SSL_load_error_strings)  SSL_load_error_strings();
  4702.     //if (ERR_load_crypto_strings) ERR_load_crypto_strings();
  4703.     // if (ERR_load_SSL_strings)    ERR_load_SSL_strings(); ???!!!
  4704.     // OpenSSL_add_all_algorithms();
  4705.     openssl_ctx = SSL_CTX_new(SSLv23_client_method());
  4706.     if (!openssl_ctx) {
  4707.       fprintf(stderr, "fatal: unable to initialize TLS: SSL_CTX_new(SSLv23_client_method)\n");
  4708.       abortLog("unable to initialize TLS: SSL_CTX_new(SSLv23_client_method)");
  4709.       assertf("unable to initialize TLS" == NULL);
  4710.     }
  4711.   }
  4712. #endif
  4713.   
  4714.   /* Init vars and thread-specific values */
  4715.   hts_initvar();
  4716.   
  4717.   /* initialiser structcheck */
  4718.   // structcheck_init(1);
  4719.  
  4720.   return 1;
  4721. }
  4722. HTSEXT_API int hts_uninit(void) {
  4723.   hts_cache_free(_hts_cache());
  4724.   hts_freevar();
  4725.   /* htswrap_free(); */
  4726.   return 1;
  4727. }
  4728.  
  4729. // defaut wrappers
  4730. void __cdecl htsdefault_init(void) {
  4731. }
  4732. void __cdecl htsdefault_uninit(void) {
  4733.   hts_freevar();
  4734. }
  4735. int __cdecl htsdefault_start(void* opt) {
  4736.   return 1; 
  4737. }
  4738. int __cdecl htsdefault_chopt(void* opt) {
  4739.   return 1;
  4740. }
  4741. int  __cdecl htsdefault_end(void) { 
  4742.   return 1; 
  4743. }
  4744. int __cdecl htsdefault_checkhtml(char* html,int len,char* url_adresse,char* url_fichier) {
  4745.   return 1;
  4746. }
  4747. int __cdecl htsdefault_loop(void* back,int back_max,int back_index,int lien_n,int lien_tot,int stat_time,hts_stat_struct* stats) {    // appelΘ α chaque boucle de HTTrack
  4748.   return 1;
  4749. }
  4750. char* __cdecl htsdefault_query(char* question) {
  4751.   return "";
  4752. }
  4753. char* __cdecl htsdefault_query2(char* question) {
  4754.   return "";
  4755. }
  4756. char* __cdecl htsdefault_query3(char* question) {
  4757.   return "";
  4758. }
  4759. int __cdecl htsdefault_check(char* adr,char* fil,int status) {
  4760.   return -1;
  4761. }
  4762. void __cdecl htsdefault_pause(char* lockfile) {
  4763.   while (fexist(lockfile)) {
  4764.     Sleep(1000);
  4765.   }
  4766. }
  4767. void __cdecl htsdefault_filesave(char* file) {
  4768. }
  4769. int __cdecl htsdefault_linkdetected(char* link) {
  4770.   return 1;
  4771. }
  4772. int __cdecl htsdefault_xfrstatus(void* back) {
  4773.   return 1;
  4774. }
  4775. int __cdecl htsdefault_savename(char* adr_complete,char* fil_complete,char* referer_adr,char* referer_fil,char* save) {
  4776.   return 1;
  4777. }
  4778. // end defaut wrappers
  4779.  
  4780.  
  4781.  
  4782. // Fin
  4783.  
  4784.